2015-09-22 2 views
3

У меня есть проект, в котором используется соглашение о декораторе, чтобы обернуть обработчики команд с помощью декораторов журналов путем перехвата открытых общих типов в StructureMap 2.6. Тем не менее, мне трудно понять, как реализовать эквивалентную функциональность в StructureMap 3, чтобы я мог завершить обновление.Перехват декоратора с открытыми дженериками в StructureMap 3

Вот код от StructureMap 2.6. Во-первых, в моем классе IoC У меня есть политики сканирования, созданной для разрешения обработчики команд:

scan.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>)); 

Далее, у меня есть декоратора конвенции, который добавляется к конвенциям сканирующих МОК, что провода до декоратора перехвата:

public class CommandLoggingDecoratorConvention : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) 
    { 
     var interfaceTypes = type.GetInterfaces(); 

     foreach (var interfaceType in interfaceTypes) 
     { 
      if (interfaceType.IsGenericType 
       && interfaceType.GetGenericTypeDefinition() == typeof(ICommandHandler<>)) 
      { 
       var arguments = interfaceType.GetGenericArguments(); 

       var closedType = typeof(CommandHandlerLoggingDecorator<>) 
        .MakeGenericType(arguments); 

       registry.For(interfaceType) 
        .EnrichWith((c, p) => Activator.CreateInstance(
         closedType, 
         p, 
         c.GetInstance<IMessageLoggingHelper>(), 
         c.GetInstance<ILog>())); 
      } 
     } 
    } 
} 

Тогда мы имеем команду шины, которая отображает конкретную команду обработчика команд и вызывает метод Execute на лесозаготовительной декоратора (который оборачивает обработчик команд), который в свою очередь вызывает метод Execute по команде внутри декоратора:

public class CommandBus : ICommandBus 
{ 
    public static IContainer Container; 

    public void Execute(ICommand command) 
    { 
     var handlerType = typeof (ICommandHandler<>) 
      .MakeGenericType(command.GetType()); 

     dynamic handler = Container 
      .GetAllInstances(handlerType) 
      .Cast<dynamic>() 
      .Single(); 

     handler.Execute((dynamic) command); 
    } 
} 

Я смог выполнить эту работу в StructureMap 3, заменив мое соглашение о декораторе политикой перехватчика и добавив политику перехватчика в классе IoC.

Вот политика перехватчик:

public class CommandLoggingDecoratorPolicy : IInterceptorPolicy 
{ 
    public string Description { get; private set; } 

    public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance) 
    { 
     if (pluginType == typeof (ICommandHandler<>)) 
      yield return new DecoratorInterceptor(
       typeof(ICommandHandler<>), 
       typeof(CommandHandlerLoggingDecorator<>)); 
    } 

А вот код, который добавляет к политике перехватчиков МОК:

x.Policies.Interceptors(new CommandLoggingDecoratorPolicy()); 

Однако, когда я называю Container.GetInstance (в моем CommandBus) его возвращает совпадающую реализацию Command Handler вместо декоратора Command Logging. Если я вызываю Container.GetAllInstances, он возвращает как реализацию (первый), так и декоратор (второй).

Итак, прямо сейчас, единственный способ, которым я могу выполнить эту работу, - это если я либо явно выбираю второй элемент, возвращаемый из Container.GetAllInstances, либо фильтрует результаты и выбирает декоратор, используя отражение. Вот пример:

public class CommandBus : ICommandBus 
{ 
    public static IContainer Container; 

    public void Execute(ICommand command) 
    { 
     var handlerType = typeof (ICommandHandler<>) 
      .MakeGenericType(command.GetType()); 

     var handlers = Container 
      .GetAllInstances(handlerType) 
      .Cast<dynamic>(); 

     var handler = handlers.ToList()[1]; 

     handler.Execute((dynamic) command); 
    } 
} 

Однако это кажется довольно уродливым решением. Очевидно, должно быть что-то, что мне не хватает. Во-первых, почему Container.GetInstance возвращает реализацию, а не декоратор, когда я явно добавил политику перехвата декоратора? Во-вторых, есть ли лучший способ, которым я должен это делать?

Любые идеи или предложения были бы высоко оценены!

+0

StructureMap 3 имеет [большую поддержку для декораторов] (https://stackoverflow.com/вопросы/30841303/определить фильтр-для-decorateallwith-методом-в-структуры-карта-3). Почему бы вам не использовать декоратор вместо перехватчика? Это делает ваш код более чистым, более ремонтопригодным и устраняет необходимость того, чтобы ваш декоратор зависел от стороннего инструмента (в этом случае библиотека перехвата). – Steven

+0

@Steven Я предполагаю, что это просто непонимание терминологии, но то, что я пытаюсь сделать, - это перехват через инфраструктуру инъекции зависимостей, чтобы обернуть обработчик команд с помощью декоратора. Однако я не пытался перехватить аспектно-ориентированную структуру программирования.Надеюсь, это устранит любую путаницу. Если нет, мне может понадобиться дополнительная информация, чтобы понять, что вы предлагаете. –

+0

А теперь я вижу «CommandHandlerLoggerDecorator ». В таком случае, пожалуйста, продолжайте то, что вы делаете. – Steven

ответ

4

Смотрите этот удивительно похожий образец (что я только что написал) в кодовой StructureMap для примера использования декораторов с родовыми типами: https://github.com/structuremap/structuremap/blob/b405d8f752b45ac250f057d9e3de8554f2a7f40f/src/StructureMap.Testing/Bugs/OpenGenericDecorator_question.cs

+0

Ваше решение отлично работает Джереми. Спасибо за быстрый ответ! :) –

+0

В случае, если кто-либо использует решение Джереми, убедитесь, что вы исключили в свою политику проверки декоратора, так что вы не получите дубликатов декораторов, возвращаемых Container.GetAllInstances(), например: 'scan.Exclude (p => p == typeof (CommandHandlerLoggingDecorator <>)); ' –

Смежные вопросы