22 September 2012

Simplifying Message Handlers

One thing I don't like about the message handler examples I've seen are all the interfaces that you have to implement. For instance:

public class CustomerHandlers : 
    IHandles<ConvertLeadToCustomer>,
    IHandles<CustomerCreditLine>,
    IHandles<CorrectCustomerAddress>
    .... // lots of these
{
    public void Handle(ConvertLeadToCustomer message)
    {
        ...
    }
    
    ... // lots of these also, but they actually do stuff
}

These interfaces help you to match up messages with the handler method and gives you something to cast the handler to in order to call the appropriate method. Ultimately it ends up like this:

    ((IHandles<T>)handler).Handle((T)message);

The first alternative I discovered was to use dynamic. I didn't have to implement all the interfaces, maybe just one interface on the parent class, and let the methods document for themselves the messages they handle. Assuming I know the right method exists on the handler (due to reflection), I can let the DLR figure out how to actually call it:

    ((dynamic)handler).Handle((dynamic)message);

Note that 3 calls to the DLR are actually made. One for the message, one for the handler, and one for the method call. This works, but you run into problems if you are lazy like me and have some event handlers that handle all events. For that I use a shortcut syntax.

public class DatabaseDenormalizer: IHandles<IEvent>
{
    public void Handle(IEvent message)
    {
        // get message's actual type name
        // call a stored procedure with same name (if it exists)
        // using events properties as parameters
    }
}

In that case, dynamic wouldn't work if you had both a generic handler method and a specific one. The generic one would never get called, because the DLR always goes for the most specific call. Also, dynamic has a bit of overhead as compared to the direct method call (but not anywhere near the slowness of a MethodInfo.Invoke() call).

Edit: Correction, MethodInfo.Invoke is only "slow" in simple tests. When the call actually does some work (and is in Release mode), Invoke can be just as fast as a direct method call.

So being the crazy person that I am, I kept looking for an alternative where I could minimally decorate my message handlers, but still have decent performance. I want them to look like this:

public class CustomerHandler : IMessageHandler
{
    public void Handle(ConvertLeadToCustomer message)
    {
        ...
    }

    public void Handle(RequestCustomerCreditLine message)

    {
        ...
    }
}

So after googling around for information many times before, I finally hit the magic combination of words today to bring me to this post from 4 years ago by Jon Skeet. The last code snippet (with some tweaking) pretty much solved my conundrum. It's admittedly pretty complex code, but I'm willing to accept that for improved performance, and easier setup on my objects, plus the complexity is on code that I will likely never touch again.

3 comments:

Karim Saidi said...

Hi, nice post. May I ask if you could share youre code to simplify message handlers : I really love this simplification and just want to adopt the same style as yours.

Kasey said...

Thanks for the comment. Based on my experiences using this style, I don't recommend it anymore. I'll write a followup post to explain why.

Karim Saidi said...

Hello, thank you for your response, could you brievely tell me more about the reason it is bad?