Внедрение AppSettings из кода с помощью Windsor 3
Я ищу способы избавления от конфигурационных файлов Windsor Xml. Я хочу оставить только необходимые настройки (в основном строки) и переместить их в AppSettings.
Есть ли хороший способ сделать это? Желательно без ручного отображения между AppSettings и зависимостями (ctor params).
Я не возражаю против реализации чего-либо, чтобы это произошло, но я хочу минимизировать стандартный код приложения для решения бизнес-задач.
3 ответа
Использование преобразователя зависимостей для ввода значений
После вашего комментария о нежелании вводить объект конфигурации я начал смотреть на некоторые из моих SubDependancyResolvers
и случайно, я гуглил, как получить имя свойства в SubDependancyResolver
и я наткнулся на фактическую реализацию. Проект находится в центре внимания и состоит из "Разных экспериментов и других йерб". Я не могу проверить, работает ли код, но он следует, как работают мои преобразователи.
Их реализация состоит из атрибута, который вы применяете к классу параметров, который сопоставляет параметры приложения в конфигурации со свойствами параметров. Альтернативой может быть наличие атрибута, который вы применяете к свойству, которое вы хотите внедрить в конструктор, и полностью избавиться от класса настроек:
public class AppSettingsAttribute: Attribute {}
public class AppSettingsResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public AppSettingsResolver(IKernel kernel)
{
this.kernel = kernel;
}
public object Resolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
if( (
from constructor in model.Constructors
from dependencyModel in constructor.Dependencies
where dependencyModel == dependency
from parameterInfo in constructor.Constructor.GetParameters()
select parameterInfo ).Any( parameterInfo => parameterInfo.Name == dependency.DependencyKey ) )
{
var converter = (IConversionManager) kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);
return converter.PerformConversion(ConfigurationManager.AppSettings[dependency.DependencyKey], dependency.TargetType);
}
return null;
}
public bool CanResolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
return (
from constructor in model.Constructors
from dependencyModel in constructor.Dependencies
where dependencyModel == dependency
from parameterInfo in constructor.Constructor.GetParameters()
where parameterInfo.Name == dependency.DependencyKey
select ( Attribute.GetCustomAttribute( parameterInfo, typeof(AppSettingsAttribute) ) != null )
).FirstOrDefault();
}
}
[ TestFixture ]
public class When_resolving_dependancies_from_the_app_settings_configuration_section
{
[ Test ]
public void Should_resolve_a_string_and_an_int()
{
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new AppSettingsResolver( container.Kernel ));
container.Register( Component.For<Dependent>() );
var dependent = container.Resolve<Dependent>();
dependent.Foo.Should().Be( "bar" );
dependent.Baz.Should().Be( 1 );
}
public class Dependent
{
public string Foo { get; private set; }
public int Baz { get; private set; }
public Dependent([AppSettings]string foo, [AppSettings]int baz)
{
Foo = foo;
Baz = baz;
}
}
}
Использование внедрения свойств с конкретными классами конфигурации
Создайте интерфейс для вашей конфигурации, а затем создайте реализацию, которая обернет ConfigurationManager.AppSettings
который вы вводите его в Виндзор как зависимость.
class SomeThingDependentOnSomeConfiguration
{
public SomeThingDependentOnSomeConfiguration(ISomeConfiguration config) { ... }
}
interface ISomeConfiguration
{
int SomeValue { get; }
string AnotherValue { get; }
}
class SomeConfigurationAppSettings : ISomeConfiguration
{
public int SomeValue
{
get
{
return Convert.ToInt32(ConfigurationManager.AppSettings["SomeValue"]);
}
}
public string AnotherValue
{
get
{
return ConfigurationManager.AppSettings["AnotherValue"];
}
}
}
Это позволяет позже ввести ConfigurationSection
(какой IMO намного чище, чем настройки приложения), или вы можете заменить его классом, который использует жестко закодированные значения, если это то, что вам нужно.
class SomeConfigurationConfigurationSections : ConfigurationSection, ISomeConfiguration
{
[ConfigurationProperty("SomeValue")]
public int SomeValue
{
get { return (int)this["SomeValue"]; }
}
[ConfigurationProperty("AnotherValue")]
public string AnotherValue
{
get { return (string)this["AnotherValue"]; }
}
}