The Inquisitive Coder – Davy Brion's Blog

Trying to walk that thin line between intelligence and ignorance

I Love Easy Extensibility

Posted by Davy Brion on March 10th, 2009

Welcome to episode 245 in my Love/Hate relationship with WCF. Today i had to add some technical logging to some infrastructure code. More specifically, we wanted to log the size of incoming and outgoing SOAP messages. If you’re using something like the Request/Response service layer you do want to keep an eye on the size of those SOAP messages to make sure nobody is going overboard with the WCF batching.

I obviously already had my service, so i just needed something that i could plug in at the appropriate moment to record the size of incoming and outgoing SOAP messages. Turns out this was extremely easy to do. First, you need to write an inspector for the messages (which has to implement WCF’s IDispatchMessageInspector interface):

    public class MessageInspector : IDispatchMessageInspector

    {

        private readonly ILog logger = LogManager.GetLogger(typeof(MessageInspector));

 

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)

        {

            if (logger.IsInfoEnabled)

            {

                logger.Info(string.Format("request message size: ~{0} KB", GetMessageLengthInKB(request)));

            }

 

            return null;

        }

 

        public void BeforeSendReply(ref Message reply, object correlationState)

        {

            if (logger.IsInfoEnabled)

            {

                logger.Info(string.Format("response message size: ~{0} KB", GetMessageLengthInKB(reply)));

            }

        }

 

        private static double GetMessageLengthInKB(Message message)

        {

            return Math.Round(Encoding.UTF8.GetBytes(message.ToString()).Length / 1024d, 2);

        }

    }

After that, you need a way to inject the MessageInspector into the behavior of your service. So you need to define your own behavior first:

    public class AddMessageInspectorBehaviorAttribute : Attribute, IServiceBehavior

    {

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {}

 

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,

            Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) {}

 

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

        {

            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)

            {

                foreach (var endpoint in dispatcher.Endpoints)

                {

                    endpoint.DispatchRuntime.MessageInspectors.Add(new MessageInspector());

                }

            }

        }

    }

And then you apply that to your service:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

    [AddMessageInspectorBehavior]

    public class WcfRequestProcessor : IRequestProcessor

    {

        // the service stuff...

    }

And that was it! I was afraid i was going to have to figure out which one of WCF’s 12.4 billion configuration options would make this possible but this actually didn’t require any configuration at all. Which is very nice, IMO.

On a side note, if anyone knows of a better way to calculate the real size of a SOAP message, please let me know :)

2 Responses to “I Love Easy Extensibility”

  1. Reflective Perspective - Chris Alcock » The Morning Brew #304 Says:

    [...] I Love Easy Extensibility – Davy Brion talks about how the extensibility model in WCF allowed him to easily add monitoring of the size of the inbound and outbound SOAP requests in the system he is working on. [...]

  2. The Inquisitive Coder - Davy Brion’s Blog » Blog Archive » Calculating The Size Of SOAP Messages Says:

    [...] I Love Easy Extensibility [...]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>