Micah
Micah

Reputation: 116070

How can I pre-process a message in nservicebus?

I want to initialize some logging when a message comes in like this:

public class BaseMessage
{
    public long TraceID { get; set; }
}

public class MyMessage : BaseMessage, ICommand
{
    //..other properties
}

public class Handler : IHandleMessages<MyMessage>
{
    public void Handle(MyMessage message)
    {
        log4net.ThreadContext.Properties["TraceID"] = message.TraceID

        //Process message
    }
}

The problem is I have a LOT of messages and I want to do this for all of them when a message comes in. I would like to be able to do something like this:

public class Handler : IInitializeHandlers, IHandleMessages<MyMessage>
{
    public void Init(BaseMessage message)
    {
        log4net.ThreadContext.Properties["TraceID"] = ((BaseMessage)message).TraceID
    }


    public void Handle(MyMessage message)
    {
        //Process message
    }
}

Upvotes: 0

Views: 490

Answers (2)

Micah
Micah

Reputation: 116070

Here's how I solved it. I wanted to automatically create the Trace ID and send it in the body of the message rather than a header. I wasn't sure about the thread-safety of adding headers to the bus and I didn't want to have to change all of the calling code or modify ever IHandleMessages implementation. So here's what I came up with.

public class TraceIDMutator : IMutateIncomingMessages, IMutateOutgoingMessages
{
    public object MutateIncoming(object message)
    {
        var baseMsg = message as MessageBase;
        if (baseMsg != null)
            ThreadContext.Properties[Constants.TraceID] = baseMsg.TraceID;

        return message;
    }

    public object MutateOutgoing(object message)
    {
        var baseMsg = message as MessageBase;
        if(baseMsg != null)
        {
            if(baseMsg.TraceID == 0)
            {
                 var tid = ThreadContext.Properties[Constants.TraceID];
                 if (tid != null)
                     baseMsg.TraceID = (ulong)tid;
            }
        }

        return message;
    }
}

The IMutateIncomingMessages and IMutateOutgoingMessagesinterfaces allow me to tap in to the messaging pipeline of nservicebus. I only discovered it after digging through source code to figure out what was actually going on under the hood. You need to register this class with your IoC container in order for it to work.

        ObjectFactory.Configure(x =>
        {
            x.For<IMutateIncomingMessages>().Use<TraceIDMutator>();
            x.For<IMutateOutgoingMessages>().Use<TraceIDMutator>();
        });

When the message is sent 'MutateOutgoing' will be called. At that point I grab the current trace id from the log4net.ThreadContext if there is one and assign it to the message. When the message is received the MutateIncoming is called and then I set the log4net.ThreadContext trace id property for that thread.

Upvotes: 0

Andreas &#214;hlund
Andreas &#214;hlund

Reputation: 5273

Move the trace id to a header instead and use a unit of work(IManageUnitsOfWork) to register it with the log4net context

Upvotes: 1

Related Questions