C# 如何使用unity+;单位自动注册
今天看完这本书后,我开始了一个有趣的转变。我想看看是否可以使用Unity而不是Union来实现该模式,到目前为止,这是非常困难的 我要做的第一件事是安装以解析opengenericC# 如何使用unity+;单位自动注册,c#,.net,dependency-injection,unity-container,simple-injector,C#,.net,Dependency Injection,Unity Container,Simple Injector,今天看完这本书后,我开始了一个有趣的转变。我想看看是否可以使用Unity而不是Union来实现该模式,到目前为止,这是非常困难的 我要做的第一件事是安装以解析opengenericICommandHandler接口。目前这方面的解决方案如下: Container = new UnityContainer().LoadConfiguration(); Container.ConfigureAutoRegistration() .ExcludeSystemAssemblies()
ICommandHandler
接口。目前这方面的解决方案如下:
Container = new UnityContainer().LoadConfiguration();
Container.ConfigureAutoRegistration()
.ExcludeSystemAssemblies()
.Include(type => type.ImplementsOpenGeneric(typeof(ICommandHandler<>)),
(t, c) => c.RegisterType(typeof(ICommandHandler<>), t)
)
.ApplyAutoRegistration()
;
Container=newunitycontainer().LoadConfiguration();
Container.ConfigureAutoRegistration()
.ExcludeSystemAssembly()除外
.Include(type=>type.implementsPengeneric(typeof(ICommandHandler)),
(t,c)=>c.RegisterType(typeof(ICommandHandler),t)
)
.ApplyAutoRegistration()
;
这适用于第一部分,解析任何单个ICommandHandler
。到目前为止,令人沮丧的是实现了一个装饰处理程序。当我添加第二个ICommandHandler
作为装饰器时,Unity就会抛出一个StackOverflowException。我对Unity内部的了解还不够,但我猜这是因为它无法确定要解析到哪个实例——命令处理程序或命令处理程序装饰器——因为两者都实现了ICommandHandler
接口
Google围绕着我,它解释了如何用我所认为的蛮力方法去做。我也发现,但没有一个能完全解决我的问题(我太无知了,自己也弄不明白)
然后我发现。然而,beefy的解决方案没有考虑处理开放泛型。目前,我们的大多数依赖项都是从.config文件的unity部分加载的,所以我不想为每个处理程序或装饰程序编写大量编译代码。看起来采用某种UnityContainerExtension和DecororBuild策略是正确的做法,但我不明白。我一直在玩比菲的代码有一段时间了,现在完全卡住了。我试图修改他的代码以解释泛型,这导致了BadImageFormatException(试图加载格式不正确的程序。(来自HRESULT的异常:0x8007000B))
我喜欢这样做来实现decorator链接,因为它很短,每个关注点只有一行:
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<>));
var container=newcontainer();
//查看所有程序集并注册所有实现
//ICommandHandler的关闭接口:
container.RegisterManyForOpenGeneric(typeof(ICommandHandler)),
AppDomain.CurrentDomain.GetAssemblys());
//用一个
//TransactionCommandHandlerDecorator。
容器.注册表记录器(类型为(ICommandHandler),
类型(TransactionCommandHandlerDecorator));
//用一个
//DeadlockRetryCommandHandlerDecorator。
容器.注册表记录器(类型为(ICommandHandler),
类型(DeadlockRetryCommandHandlerDecorator);
…但如果不需要的话,我不想将容器从Unity更改为Simple Injector
所以我的问题是,我如何使用unity(加上
UnityAutoRegistration
)实现开放的泛型装饰链接?我希望我正确地理解了这个问题,我很好奇尝试让它工作起来,我绝对不是Unity方面的专家,但我正在考虑一个更容易实现的解决方案,也更容易使用不同的容器。似乎支持开放泛型和其他类型的唯一方法是有两个单独的容器(一个用于开放泛型),另一个用于命令处理程序,这可能不是最好的方法,但它与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")));
//查找所有程序集并注册所有实现a-
//ICommandHandler通过其关闭的接口执行以下操作:
var container=new UnityContainer();
var handlerRegistrations=
来自AppDomain.CurrentDomain.GetAssemblys()中的程序集
来自assembly.GetExportedTypes()中的实现
哪里执行
哪里implementation.ContainsGenericParameters
出租服务=
来自实现中的iface.GetInterfaces()
其中iface.IsGenericType
其中iface.GetGenericTypeDefinition()==
类型(ICommandHandler)
选择iface
从服务到服务
选择新{服务,实现};
foreach(handlerRegistrations中的var注册)
{
container.RegisterType(registration.service,
注册、实施,“内部1”);
}
//用一个
//TransactionCommandHandlerDecorator。
container.RegisterType(typeof(ICommandHandler),
类型(TransactionCommandHandlerDecorator),
“Inner2”,
InjectionConstructor(新的ResolvedParameter(
类型(ICommandHandler),“Inner1”);
//用一个
//DeadlockRetryCommandHandlerDecorator。
container.RegisterType(typeof(ICommandHandler),
类型(DeadlockRetryCommandHandlerDecorator),
InjectionConstructor(新的ResolvedParameter(
类型(ICommandHandler),“Inner2”);
我必须说,我发现您的解决方案非常有创意,因此+1表示支持。然而,拥有多个容器将不幸成为维护的一大噩梦。这两个容器都需要维护,而且由于要显式地更新装饰器,因此需要手动注入所有依赖项。但更重要的是,在注册服务的生命周期中,您会遇到一些非常奇怪的行为……例如,TryCatchCommandHandler
和真实的命令处理程序都依赖于您注册的ILogger
接口
public class DecoratorCommandHandler<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> inner;
public DecoratorCommandHandler(
ICommandHandler<TCommand> inner)
{
this.inner = inner;
}
public virtual void Handle(TCommand command)
{
this.inner.Handle(command);
}
}
public class DecoratedHandler<TCommand>
: DecoratorCommandHandler<TCommand>
{
public DecoratedHandler(UnityContainer container)
: base(BuildInner(container))
{
}
private static ICommandHandler<TCommand> BuildInner(
UnityContainer container)
{
var handlerContainer =
container.Resolve<UnityContainer>("Handlers");
var commandHandler =
handlerContainer.Resolve<ICommandHandler<TCommand>>();
return new TryCatchCommandHandler<TCommand>(commandHandler);
}
}
ICommandHandler<QueryCommand> handler =
container.Resolve<ICommandHandler<QueryCommand>>();
var cmd = new QueryCommand();
handler.Handle(cmd);
// 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")));