Замок Виндзор использует идентификатор компонента / имя в качестве параметра
У меня есть проект, в котором я использую Castle Windsor для внедрения зависимостей, более конкретно, я использую конфигурацию XML, поэтому общая служба может работать по-разному в зависимости от параметров.
Например (действительно упрощенно):
<component id="Processors" service="System.Collections.Generic.IEnumerable`1[[Services.Interfaces.IProcessor, Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]" type="System.Collections.Generic.List`1[[Services.Interfaces.IProcessor, Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]">
<parameters>
<collection>
<list>
<item>${Processor1}</item>
<item>${Processor2}</item>
</list>
</collection>
<parameters>
</component>
<component id="Processor1" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>LIVE</example>
<id>Processor1</id>
</parameters>
</component>
<component id="Processor2" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>TEST</example>
<id>Processor2</id>
</parameters>
</component>
Во время выполнения мы разрешаем компонент с именем Processors и перебираем все элементы, вызывающие каждый из них по очереди.
Как вы можете видеть в приведенном выше примере, у нас есть параметр с именем id на каждом из процессоров, он в основном используется для регистрации и действительно полезен для отслеживания того, у какого процессора возникла проблема (и через прокси-конфигурацию). В идеале было бы неплохо, если бы я мог повторно использовать идентификатор из конфигурации компонента (уменьшив конфигурацию).
Любые идеи о том, как это можно сделать?
1 ответ
Для использования части "идентификатор компонента / имя в качестве параметра" можно определить Castle.MicroKernel.ISubDependencyResolver
Например, вот так:
public class InjectIdSubDependencyResolver : ISubDependencyResolver
{
private const string SpecialName = "id";
public bool CanResolve(
CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model, DependencyModel dependency)
=>
dependency.TargetType == typeof(string)
&&
dependency.DependencyKey == SpecialName
&&
dependency.Parameter?.ConfigValue == null;
public object Resolve(
CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model, DependencyModel dependency)
=> model.Name;
}
Вы настроили это так:
IWindsorContainer wc = ...;
wc.Kernel.Resolver.AddSubResolver(new InjectIdSubDependencyResolver());
Тогда XML-конфигурация упрощается...
<component id="Processor1" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>LIVE</example>
</parameters>
</component>
<component id="Processor2" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>TEST</example>
</parameters>
</component>
Заметка
Кроме того, вместо регистрации общего списка в контейнере я бы использовал второй класс вместе с решателем Sub Sub Dependency, то есть
public class Processors {
public Processors(IEnumerable<IProcessor> collection) { /**/ }
}
... или даже попытаться использовать Типизированные Фабрики
Надеюсь, поможет.