问题描述
在阅读了这篇关于命令处理程序的文章后,今天开始了一个有趣的切入点装饰.我想看看我是否可以使用 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 打开通用装饰器链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!