怎么办开放式泛型装饰与团结+ UnityAutoRegistration链接开放式、团结、链接、UnityAutoRegistration

2023-09-02 02:01:02 作者:离开吧.

今天一个有趣的切线去了阅读本文就命令处理程序后,装修。我想看看我是否能实现使用统一而不是 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< TCommand> 接口。对于这方面目前的解决方案如下:

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&LT; TCommand&GT; 。什么是令人沮丧的证明迄今实施装饰处理。当我添加第二个 ICommandHandler&LT; TCommand&GT; 作为装饰,统一抛出一个StackOverflowException。我不知道有足够的了解团结内部,但我猜这是因为它不能找出解决这些实例 - 命令处理程序,或命令处理程序装饰 - 因为这两个实施 ICommandHandler&LT; TCommand&GT; 接口

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.

周围的Googling导致我首先这篇文章,这也解释了如何做到这一点的我会考虑一个强制的方法。我还发现这些 related 页面但都不是一个完整的解决我的问题(和我太无知的数字出来为自己)。

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).

我后来发现这篇文章中,这似乎解决我同样的问题的。但结实的解决方案并没有考虑处理开放的仿制药。目前我国大部分依赖的是从config文件的统一体部分加载,所以我不想写一吨的编译code每个处理或装饰。好像有某种UnityContainerExtension和DecoratorBuildStrategy是正确的路要走,但我不能弄明白。我一直在玩健壮的code一小会儿,现在,我完全被卡住。我试图修改他的code占仿制药,导致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我的容器,以简单的注射,如果我没有。

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

所以我的问题是我怎么可能去实现开放一般装饰用的统一链(加上 UnityAutoRegistration )?

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

推荐答案

这将是等值的统一:

// 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")));