Monday, February 7, 2011

NServiceBus 3.0: Message Mutators

In NSB 2 it was a bit more tricky to change messages as they were sent to and from endpoints.  In NSB 3 we now have a couple of simple interfaces to plug in our custom logic to change messages.  The typical scenario this is used for is to encrypt all or part of a message.  The encryption message mutator is built right in and can be used at any time.  In this article we'll show how to create a custom message mutator to simply do some math on Double fields in a message.  Let's first take a quick look at the interfaces involved.
Each interface gives us access to the message so that we can mutate on the inbound and/or outbound message.  All we have to do as a consumer is implement the desired interface and load it into the NSB container.  For my mutator, I will implement IMessageMutator and only implement the outgoing message for the time being.
public class MultiplierMutator : IMessageMutator
    {
        #region IMutateOutgoingMessages Members

        public NServiceBus.IMessage MutateOutgoing(NServiceBus.IMessage message)
        {
            var doubles = message.GetType().GetProperties().Where(p => typeof(double).IsAssignableFrom(p.PropertyType));

            foreach (var dbl in doubles)
            {
                double dblValue = (double)dbl.GetValue(message, null);
                dbl.SetValue(message, dblValue * 5, null);
            }

            return message;
        }

        #endregion

        #region IMutateIncomingMessages Members

        public NServiceBus.IMessage MutateIncoming(NServiceBus.IMessage message)
        {
            return message;
        }

        #endregion
    }
In this class we first find all Double fields. Once we have that list we simply multiply each field by an arbitrary number, in this case 5. The last thing we need to do is let the container know about the mutator. We do this in our implementation of IWantCustomInitialization.
NServiceBus.Configure.Instance.Configurer.ConfigureComponent<MultiplierMutator>(NServiceBus.ObjectBuilder.DependencyLifecycle.InstancePerCall);
Now we can fire up our endpoints and watch what happens. I stubbed this into the Encryption sample that comes with the NSB download. In the Client project I added a value to the Result field on the message.
while (Console.ReadLine() != null)
            {
                Bus.Send<MessageWithSecretData>(m =>
                    {
                        m.Secret = "betcha can't guess my secret";
                        m.Result = 5;
                    });
            }
Now for the output from the Server project:
So that's it! Now we can dream up any kind of change to our messages. Maybe you want to compress or hash some of the messages, it's all up to you.





1 comment:

  1. Excellent. I remember asking a question about Compressing messages a while ago to get around the 4mg limit with MSMQ.. almost too easy

    ReplyDelete