Замок Виндзор использует идентификатор компонента / имя в качестве параметра

У меня есть проект, в котором я использую 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) { /**/ }
}

... или даже попытаться использовать Типизированные Фабрики

Надеюсь, поможет.

Другие вопросы по тегам