2014-11-14 42 views
2

单消息处理厂因此,我有叫IMessage。然后我有类,比如一个标记接口:使用Autofac

public class MessageA: IMessage 
{ 
} 

然后我就消息处理程序定义为:

internal interface IMessageHandler<in T> where T: IMessage 
{ 
    void Handle(T message); 
} 

public class MessageAHandler : IMessageHandler<MessageA> 
{ 
    public void Handle(T message) 
    { 
     //Some logic here 
    } 
} 

我要重新 - 当我收到新消息时,将这些消息路由到相应的消息处理程序。例如:

public class MessageReceiver 
{ 
    public void ReceiveMessage(IMessage message) 
    { 
     //somehow resolve the appropiate message handler here 

     messageHandler.Handle(message); 
    } 
} 

我可以通过工厂像下面现在做到这一点正确的,但我需要有每个不同类型的消息的每一个新工厂的依赖。所以我想知道是否有办法创建一个足够聪明的单个工厂来解析合适的消息处理程序?

public class MessageReceiver 
{ 
    private readonly Func<IMessageHandler<MessageA>> _messageAFactory; 

    public MessageReceiver(Func<IMessageHandler<MessageA>> messageAFactory) 
    { 
     _messageAFactory= messageAFactory; 
    } 

    public void ReceiveMessage(IMessage message) 
    { 
     if (message is MessageA) 
     { 
      var messageHandler = _messageAFactory(); 
      messageHandler.Handle(message as MessageA); 
     } 

     // Add more if-statements here for more messages 
    } 
} 

Autofac注册

public class InfrastructureModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     //Register the types in the infrastructure assembly 
     builder.RegisterAssemblyTypes(ThisAssembly).AsImplementedInterfaces() 
      .InstancePerLifetimeScope(); 

     //Register the message handlers 
     builder.RegisterAssemblyTypes(ThisAssembly) 
     .Where(x => x.IsAssignableFrom(typeof(IMessageHandler<IMessage>))) 
     .InstancePerDependency().AsImplementedInterfaces(); 
    } 
} 
+0

如果我理解正确,你有每个消息的工厂?您可以使用IIndex (http://docs.autofac.org/en/latest/advanced/keyed-services.html) – MHGameWork 2014-11-15 13:19:30

+0

此外,这可能有所帮助:http://stackoverflow.com/questions/25003048/keyed-delegate-factories-with-runtime-constructor-parameters – MHGameWork 2014-11-15 13:20:45

+0

是的,我有一个每个消息处理程序的工厂(每个消息类型有一个消息处理程序)。感谢您的链接。 – fgauna 2014-11-16 16:41:19

回答

3

首先我会为你的消息,只是一个基本的处理标记一个小的实现,为了测试

public class MessageA : IMessage 
{ 
    public bool Handled 
    { 
     get; 
     private set; 
    } 

    public void MarkAsHandled() 
    { 
     this.Handled = true; 
    } 
} 

public class MessageB : IMessage 
{ 
    public bool Handled 
    { 
     get; 
     private set; 
    } 

    public void MarkAsHandled() 
    { 
     this.Handled = true; 
    } 
} 

现在,让我们执行这两个处理程序为:

public class MessageAHandler : IMessageHandler<MessageA> 
{ 
    public void Handle(MessageA message) 
    { 
     message.MarkAsHandled(); 
    } 
} 

public class MessageBHandler : IMessageHandler<MessageB> 
{ 
    public void Handle(MessageB message) 
    { 
     message.MarkAsHandled(); 
    } 
} 

作为一个方面说明,您可能希望将IMessageHandler接口标记为公共(如果可见性设置为内部,则会出现编译器错误)。

现在让我们添加一个小的处理程序:

public interface IMessageHandler 
{ 
    Type MessageType { get; } 
    void Handle(IMessage message); 
} 

public class MessageHandlerAdapter<T> : IMessageHandler where T : IMessage 
{ 
    private readonly Func<IMessageHandler<T>> handlerFactory; 

    public MessageHandlerAdapter(Func<IMessageHandler<T>> handlerFactory) 
    { 
     this.handlerFactory = handlerFactory; 
    } 

    public void Handle(IMessage message) 
    { 
     var handler = handlerFactory(); 
     handler.Handle((T)message); 
    } 

    public Type MessageType 
    { 
     get { return typeof(T); } 
    } 
} 

我们现在可以实现的messageReceiver这样:

public class MessageReceiver 
{ 
    private readonly IEnumerable<IMessageHandler> handlers; 

    public MessageReceiver(IEnumerable<IMessageHandler> handlers) 
    { 
     this.handlers = handlers; 
    } 

    public void ReceiveMessage(IMessage message) 
    { 
     var handler = this.handlers.Where(h => h.MessageType == message.GetType()).FirstOrDefault(); 

     if (handler != null) 
     { 
      handler.Handle(message); 
     } 
     else 
     { 
      //Do something here, no handler found for message type 
     } 
    } 
} 

现在来测试我们的信息被正确处理,这里是一个小测试:

[TestClass] 
public class TestSelector 
{ 
    private IContainer container; 

    [TestMethod] 
    public void TestMethod() 
    { 
     var processor = container.Resolve<MessageReceiver>(); 

     MessageA ma = new MessageA(); 
     MessageB mb = new MessageB(); 

     processor.ReceiveMessage(ma); 
     processor.ReceiveMessage(mb); 

     Assert.AreEqual(ma.Handled, true); 
     Assert.AreEqual(mb.Handled, true); 

    } 
} 

而且我们需要修改注册,如果选择手动注册离子,我们做如下:

public TestSelector() 
    { 
     var containerBuilder = new ContainerBuilder(); 

     containerBuilder.RegisterType<MessageAHandler>().As<IMessageHandler<MessageA>>(); 
     containerBuilder.RegisterType<MessageBHandler>().As<IMessageHandler<MessageB>>(); 

     containerBuilder.RegisterType<MessageHandlerAdapter<MessageA>>().As<IMessageHandler>(); 
     containerBuilder.RegisterType<MessageHandlerAdapter<MessageB>>().As<IMessageHandler>(); 

     containerBuilder.RegisterType<MessageReceiver>(); 

     this.container = containerBuilder.Build(); 
    } 

在这里,我们现在需要注册一个处理程序和相关的适配器。

它也当然可以进行组装扫描,但这需要多一点点的细节问题,因为使用:

builder.RegisterAssemblyTypes(ThisAssembly) 
    .Where(x => x.IsAssignableFrom(typeof(IMessageHandler<IMessage>))) 
    .InstancePerDependency().AsImplementedInterfaces(); 

将无法​​正常工作

typeof(MessageAHandler).IsAssignableFrom(typeof(IMessageHandler<IMessage>)) 

将返回false,因为MessageAHandler实现IMessageHandler,而不是IMessageHandler

要做自动发现和注册,这里是一个片段:

public TestSelector() 
    { 
     var containerBuilder = new ContainerBuilder(); 

     Func<Type, Type> GetHandlerInterface = (t) => t.GetInterfaces() 
      .Where(iface => iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IMessageHandler<>)).FirstOrDefault(); 

     var handlerTypes = typeof(IMessage).Assembly.GetTypes() 
      .Where(type => type.IsClass 
       && !type.IsAbstract 
       && GetHandlerInterface(type) != null); 

     foreach (Type handlerType in handlerTypes) 
     { 
      Type messageType = GetHandlerInterface(handlerType).GetGenericArguments()[0]; 
      var genericHandler = typeof(MessageHandlerAdapter<>).MakeGenericType(messageType); 

      containerBuilder.RegisterType(handlerType).AsImplementedInterfaces(); 
      containerBuilder.RegisterType(genericHandler).As<IMessageHandler>(); 
     } 

     containerBuilder.RegisterType<MessageReceiver>(); 

     this.container = containerBuilder.Build(); 
    } 
+0

谢谢!回复晚了非常抱歉。我最终将你创建的第二个IMessageHandler接口重命名为IMessageHandlerAdapter,因为它对我有点困惑。同样在'ReceiveMessage'方法中,你可以使用'this.handlers.FirstOrDefault(h => h.MessageType == message.GetType());'而不是 – fgauna 2015-01-13 16:27:00

0

对于任何人谁仍在寻找自动分派给注册了适当的消息处理程序更好的解决方案,还有通过MediatR。这一个很好的实现是可以分派消息与适当登记处理真棒库,并有能力发布消息给多个处理程序。 它最适合CQRS场景,也适用于异步Web API,请参阅CQRS using MediatR。使用DI容器(如Autofac和StructuredMap)时有很好的支持,请参阅MediatR wiki的wiki页面以获取有关DI支持的全部详细信息。