Best way to put together a large collection of message handlers

I am starting work on a message processing system where a lot of messages will come from an external source and should be "processed". Message objects are mostly DTOs.

I think that message classes live in their own assembly, available both for the message processing system and for the external system, and that the handlers inherit from a common abstract class in the following approximate lines:

Messages.dll

public abstract class Message {}

public class FooMessage : Message
{
  ...
}

public class BarMessage : Message
{
  ...
}

MessageHandlers.dll

public abstract class MessageHandler<TMessage> where TMessage : Message
{
  public void Handle(TMessage message);
}

public class FooHandler : MessageHandler<FooMessage>
{
  public void Handle(FooMessage message)
  {
    ...
  }
}

: ? , , , , , IoC? - , ? .

!

+3
4

. , . :

<!-- language: c# -->
container.Register<IMessageHandler<FooMessage>, FooHandler>();
container.Register<IMessageHandler<BarMessage>, BarHandler>();
// etc

. IMessageHandler<T>.

, , . DI . , - . , :

<!-- language: c# -->
container.RegisterManyOpenGeneric(typeof(MessageHandler<>),
    typeof(MessageHandler<>).Assembly);

, MessageHandler<T> , MessageHandler<T>. , , .

, . , DI.

, , IMessageProcessor, Message:

<!-- language: c# -->
public interface IMessageProcessor
{
    void Process(Message message);
}

DI IMessageProcessor, :

<!-- language: c# -->
private class DIMessageProcessor : IMessageProcessor
{
    private readonly Container container;

    public DIMessageProcessor(Container container)
    {
        this.container = container;
    }

    public void Process(Message message)
    {
        if (message == null) throw new ArgumentNullException("message");

        Type messageType = message.GetType();

        Type handlerType =
            typeof(IMessageHandler<>).MakeGenericType(messageType);

        var handler = this.container.GetInstance(handlerType);

        handlerType.GetMethod("Handle").Invoke(handler, message);
    }
}

. , . , , ( ). IMessageProcessor. , DIMessageProcessor unit test ( ).

DIMessageProcessor, . , :

<!-- language: c# -->
container.RegisterSingle<IMessageProcessor>(new DIMessageProcessor(container));

IMessageProcessor , . WCF:

<!-- language: c# -->
[ServiceKnownType("GetKnownMessageTypes")]
public class WCFMessageService
{
    private readonly IMessageProcessor processor;

    public WCFMessageService()
    {
        this.processor = 
            Global.Container.GetInstance<IMessageProcessor>();
    }

    [OperationContract]
    public void Process(Message message)
    {
        this.processor.Process(message);
    }

    public static IEnumerable<Type> GetKnownMessageTypes(
        ICustomAttributeProvider provider)
    {
        var knownMessageTypes =
            from type in typeof(Message).Assembly.GetTypes()
            where typeof(Message).IsAssignableFrom(type)
            select type;

        return knownMessageTypes.ToArray();
    }
}

, .

+2

- , . .

0

, , ( , ):

var formatter = new BinaryFormatter();
using (var s = new MemoryStream(message.AsBytes))
{
    dynamic consumable = formatter.Deserialize(s);

    var consumerType = typeof(IMessageConsumer<>).MakeGenericType(consumable.GetType());
    dynamic consumer = this.container.Resolve(consumerType);
    consumer.Consume(consumable);
}

: https://github.com/ploeh/CQRSonAzureDemo/blob/master/BookingWorkerRole/AzureQueueMessageProcessor.cs

0

Request/Response, Agatha (agatha-rrsl). , , , , WCF.

, , IoC (Windsor, StructureMap, Unity, Spring.NET, Ninject), .

, .

0

All Articles