如何使用 unity + UnityAutoRegistration 打开通用装饰器链接 [英] How to do open generic decorator chaining with unity + UnityAutoRegistration

查看:28
本文介绍了如何使用 unity + UnityAutoRegistration 打开通用装饰器链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读了这篇关于命令处理程序的文章后,今天开始了一个有趣的切入点装饰.我想看看我是否可以使用 Unity 而不是 SimpleInjector 来实现该模式,但到目前为止,它被证明非常困难.

Went off on an interesting tangent today after reading this article on command handler decoration. I wanted to see if I could implement the pattern using Unity instead of SimpleInjector, and so far it is proving extremely difficult.

我必须做的第一件事是安装 UnityAutoRegistration 来解决开放的通用 ICommandHandler; 界面.目前该方面的解决方案如下:

The first thing I had to do was install UnityAutoRegistration to resolve the open generic ICommandHandler<TCommand> interface. Current solution for that aspect is as follows:

Container = new UnityContainer().LoadConfiguration();

Container.ConfigureAutoRegistration()
    .ExcludeSystemAssemblies()
    .Include(type => type.ImplementsOpenGeneric(typeof(ICommandHandler<>)),
        (t, c) => c.RegisterType(typeof(ICommandHandler<>), t)
    )
    .ApplyAutoRegistration()
;

这适用于第一部分,解决任何单个 ICommandHandler.到目前为止,令人沮丧的是实现装饰处理程序.一旦我添加第二个 ICommandHandler 作为装饰器,Unity 就会抛出 StackOverflowException.我对 Unity 内部的了解还不够多,但我猜这是因为它无法确定要解析到哪个实例——命令处理程序或命令处理程序装饰器——因为两者都实现了 ICommandHandler<TCommand> 接口.

This works for the first part, resolving any single ICommandHandler<TCommand>. What's proven frustrating so far is implementing a decoration handler. As soon as I add a second ICommandHandler<TCommand> as a decorator, Unity throws a StackOverflowException. I don't know enough about Unity internals, but I'm guessing this is because it can't figure out which instance to resolve to -- the command handler, or the command handler decorator -- since both implement the ICommandHandler<TCommand> interface.

谷歌搜索使我首先阅读这篇文章,它解释了如何在我认为是蛮力方法.我还发现了这些 相关 pages 但没有一个是我问题的完整解决方案(而且我太无知而无法自己弄清楚).

Googling around led me first to this article, which explains how to do it in what I would consider a brute force method. I also found these related pages but none is a complete solution to my problem (and I am too ignorant to figure it out for myself).

然后我找到了这篇文章,它似乎解决了我同样的问题.然而,beefy 的解决方案没有考虑处理开放泛型.目前,我们的大部分依赖项都是从 .config 文件的 unity 部分加载的,因此我不想为每个处理程序或装饰器编写大量编译代码.似乎拥有某种 UnityContainerExtension 和 DecoratorBuildStrategy 是正确的方法,但我无法弄清楚.我已经玩了很长一段时间了,但我完全卡住了.我尝试修改他的代码以考虑泛型导致了 BadImageFormatExceptions(尝试加载格式不正确的程序.(来自 HRESULT 的异常:0x8007000B)).

I then found this article, which seems to address my same concerns. However beefy's solution does not account for dealing with open generics. Currently most of our dependencies are loaded from a unity section in the .config file, so I don't want to write a ton of compiled code for each handler or decorator. It seems like having some kind of UnityContainerExtension and DecoratorBuildStrategy is the right way to go, but I can't figure it out. I have been playing with beefy's code for a little while now, and am completely stuck. My attempts to modify his code to account for generics has led to BadImageFormatExceptions (An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)).

我喜欢这样做来实现装饰器链的想法,因为它很短,而且每个关注点只有 1 行:

I like the idea of doing this to implement the decorator chaining, because it's short, and there is only 1 line per concern:

var container = new Container();

// Go look in all assemblies and register all implementations
// of ICommandHandler<T> by their closed interface:
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>),
    AppDomain.CurrentDomain.GetAssemblies());

// Decorate each returned ICommandHandler<T> object with an
// TransactionCommandHandlerDecorator<T>.
container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>));

// Decorate each returned ICommandHandler<T> object with an
// DeadlockRetryCommandHandlerDecorator<T>.
container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(DeadlockRetryCommandHandlerDecorator<>));

...但如果我不需要,我不想将我的容器从 Unity 更改为 Simple Injector.

...but I don't want to change my container from Unity to Simple Injector if I don't have to.

所以我的问题是如何使用 unity(加上 UnityAutoRegistration)来实现开放的通用装饰器链?

SO my question is how could I go about implementing open generic decorator chaining using unity (plus UnityAutoRegistration)?

推荐答案

这在 Unity 中是等效的:

This would be the equivalent in Unity:

// Go look in all assemblies and register all implementa-
// tions of ICommandHandler<T> by their closed interface:
var container = new UnityContainer();

var handlerRegistrations =
    from assembly in AppDomain.CurrentDomain.GetAssemblies()
    from implementation in assembly.GetExportedTypes()
    where !implementation.IsAbstract
    where !implementation.ContainsGenericParameters
    let services =
        from iface in implementation.GetInterfaces()
        where iface.IsGenericType
        where iface.GetGenericTypeDefinition() == 
            typeof(ICommandHandler<>)
        select iface
    from service in services
    select new { service, implementation };

foreach (var registration in handlerRegistrations)
{
    container.RegisterType(registration.service, 
        registration.implementation, "Inner1");
}

// Decorate each returned ICommandHandler<T> object with an
// TransactionCommandHandlerDecorator<T>.
container.RegisterType(typeof(ICommandHandler<>), 
    typeof(TransactionCommandHandlerDecorator<>),
    "Inner2",
    InjectionConstructor(new ResolvedParameter(
        typeof(ICommandHandler<>), "Inner1")));

// Decorate each returned ICommandHandler<T> object with an
// DeadlockRetryCommandHandlerDecorator<T>.
container.RegisterType(typeof(ICommandHandler<>), 
    typeof(DeadlockRetryCommandHandlerDecorator<>), 
    InjectionConstructor(new ResolvedParameter(
        typeof(ICommandHandler<>), "Inner2")));

这篇关于如何使用 unity + UnityAutoRegistration 打开通用装饰器链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆