How to decorate interfaces bound to more than one concrete type with Ninject

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-22 08:35:01

问题


So, I have a message bus that instantiates message handlers through Ninject. I'd like to decorate my handlers with cross cutting concerns such as logging, transaction management, etc.

I setup my bindings like so:

kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>()
    .WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>));

Which works fantastically whenever I have a single handler of a specific message type. However, when I have more than one handler defined:

kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>()
    .WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind<IMessageHandler<int>>().To<IntHandlerTwo>()
    .WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>));

Ninject will find and inject the decorator to the message bus, and then attempt unsuccessfully to inject both handlers into the decorator constructor.

public HandlerDecorator(IMessageHandler<T> handler)

You may be thinking, why don't I just modify my decorator to accept the list of handlers? I thought about this, but that defeats the purpose of the handler. I want to be able to easily chain multiple decorators together transparently. Each instance of IMessageHandler<T> should get an entirely new chain of handlers.

I've published an example test library on GitHub that should illustrate what I'm talking about here.

Is there any way to do this in Ninject?


回答1:


Use

kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>().WhenParentNamed("One");
kernel.Bind<IMessageHandler<int>>().To<IntHandlerTwo>().WhenParentNamed("Two");
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>)).Named("One");
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>)).Named("Two");

Also be aware that most of the Bus Frameworks have some way to do decorations for message handlers. May have a look there first.




回答2:


You should wrap those handlers in a composite:

public class CompositeMessageHandler<T> : IMessageHandler<T>
{
    private readonly IEnumerable<IMessageHandler<T>> handlers;

    CompositeMessageHandler(IEnumerable<IMessageHandler<T>> handlers)
    {
        this.handlers = handlers;
    }

    public void Handle(T message)
    {
        foreach (var handler in this.handlers)
        {
            handler.Handle(message);
        }
    }
}

This composite can again be injected into your decorator. Or perhaps you should do it the other way around: Wrap each handler with a decorator and wrap those into the composite.

I'm not sure how to register this with Ninject though.



来源:https://stackoverflow.com/questions/13278958/how-to-decorate-interfaces-bound-to-more-than-one-concrete-type-with-ninject

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!