简体   繁体   English

在StructureMap中使用Open Generics进行装饰器拦截3

[英]Decorator Interception with Open Generics in StructureMap 3

I have a project that is using a decorator convention to wrap command handlers with logging decorators via interception of open generic types in StructureMap 2.6. 我有一个项目,它使用装饰器约定通过截取StructureMap 2.6中的开放泛型类型来包装带有日志装饰器的命令处理程序。 However, I'm having difficulty figuring out the best way to implement the equivalent functionality in StructureMap 3 so that I can complete the upgrade. 但是,我很难找到在StructureMap 3中实现等效功能的最佳方法,以便我可以完成升级。

Here's the code from StructureMap 2.6. 这是StructureMap 2.6的代码。 First, in my IoC class I have a scanning policy set up to resolve the command handlers: 首先,在我的IoC类中,我设置了一个扫描策略来解析命令处理程序:

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

Next, I have a decorator convention, which is added to the IoC's scanning conventions, that wires up the decorator interception: 接下来,我有一个装饰器约定,它被添加到IoC的扫描约定中,用于连接装饰器拦截:

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>()));
            }
        }
    }
}

Then, we have a command bus which maps a specific command to a command handler and calls the Execute method on the logging decorator (which is wrapping the command handler) which in turns calls the Execute method on the command inside of the decorator: 然后,我们有一个命令总线,它将一个特定的命令映射到一个命令处理程序,并在日志装饰器(包装命令处理程序)上调用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);
    }
}

I have been able to make this work in StructureMap 3 by replacing my decorator convention with an interceptor policy and adding the interceptor policy in the IoC class. 通过用拦截器策略替换我的装饰器约定并在IoC类中添加拦截器策略,我已经能够在StructureMap 3中完成这项工作。

Here's the interceptor policy: 这是拦截器政策:

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<>));
    }

And here's the code that adds it to the IoC's interceptor policies: 以下是将其添加到IoC的拦截器策略中的代码:

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

However, when I call Container.GetInstance (in my CommandBus) it returns the matching Command Handler implementation instead of the Command Logging decorator. 但是,当我调用Container.GetInstance(在我的CommandBus中)时,它返回匹配的Command Handler实现而不是Command Logging装饰器。 If I call Container.GetAllInstances, it returns both the implementation (first) and the decorator (second). 如果我调用Container.GetAllInstances,它将返回实现(第一个)和装饰器(第二个)。

So, right now, the only way I am able to make this work is if I either explicitly choose the second item returned from Container.GetAllInstances or filter the results and choose the decorator using reflection. 所以,现在,我能够做到这一点的唯一方法是,如果我明确选择从Container.GetAllInstances返回的第二个项目,或者过滤结果并使用反射选择装饰器。 Here's an example: 这是一个例子:

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);
    }
}

However, this seems like a pretty ugly solution. 然而,这似乎是一个非常难看的解决方案。 There clearly must be something that I'm missing. 显然必须有一些我不知道的东西。 First, why is Container.GetInstance returning the implementation rather than the decorator when I've explicitly added a decorator interception policy? 首先,当我明确添加装饰器拦截策略时,为什么Container.GetInstance返回实现而不是装饰器? Second, is there a better way that I should be doing this altogether? 第二,我应该更好地完成这项工作吗?

Any ideas or suggestions would be greatly appreciated! 任何想法或建议将不胜感激!

有关使用具有泛型类型的装饰器的示例,请参阅StructureMap代码库中的这个非常相似的示例(我刚刚写的): https//github.com/structuremap/structuremap/blob/b405d8f752b45ac250f057d9e3de8554f2a7f40f/src/StructureMap.Testing/Bugs/OpenGenericDecorator_question的.cs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM