C# 如何使用unity+;单位自动注册

C# 如何使用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()

今天看完这本书后,我开始了一个有趣的转变。我想看看是否可以使用Unity而不是Union来实现该模式,到目前为止,这是非常困难的

我要做的第一件事是安装以解析opengeneric
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")));