Using a WCF Message Inspector to extend AppFabric Monitoring

I read through Ron Jacobs post on Monitoring WCF Data Services with AppFabric

http://blogs.msdn.com/b/endpoint/archive/2010/06/09/tracking-wcf-data-services-with-windows-server-appfabric.aspx

What is immediately striking are 2 things – it’s so easy to get monitoring data into a viewer (AppFabric Dashboard) w/ very little work.  And the 2nd thing is, why can’t this be a WCF message inspector on the dispatch side.

So, I took the base class WCFUserEventProvider that’s located in the WCF/WF samples [1] in the following path, \WF_WCF_Samples\WCF\Basic\Management\AnalyticTraceExtensibility\CS\WCFAnalyticTracingExtensibility\  and then created a few classes that project the injection as a IEndPointBehavior

There are just 3 classes to drive injection of the inspector at runtime via config:

  1. IDispatchMessageInspector implementation
  2. BehaviorExtensionElement implementation
  3. IEndpointBehavior implementation

The full source code is below with a link to the solution file here: [Solution File]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using Microsoft.Samples.WCFAnalyticTracingExtensibility;

namespace Fabrikam.Services
{
public class AppFabricE2EInspector : IDispatchMessageInspector
{
static WCFUserEventProvider evntProvider = null;
static AppFabricE2EInspector()
{
evntProvider = new WCFUserEventProvider();
}

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

        OperationContext ctx = OperationContext.Current;
        var opName = ctx.IncomingMessageHeaders.Action;

        evntProvider.WriteInformationEvent("start", string.Format("operation: {0} at address {1}", opName, ctx.EndpointDispatcher.EndpointAddress));
        return null;
    }

    public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        OperationContext ctx = OperationContext.Current;
        var opName = ctx.IncomingMessageHeaders.Action;

        evntProvider.WriteInformationEvent("end", string.Format("operation: {0} at address {1}", opName, ctx.EndpointDispatcher.EndpointAddress));
        
    }
}

public class AppFabricE2EBehaviorElement : BehaviorExtensionElement
{

    #region BehaviorExtensionElement
    /// <summary>
    /// Gets the type of behavior.
    /// </summary>
    /// <value></value>
    /// <returns>The type that implements the end point behavior<see cref="T:System.Type"/>.</returns>
    public override Type BehaviorType
    {
        get { return typeof(AppFabricE2EEndpointBehavior); }
    }

    /// <summary>
    /// Creates a behavior extension based on the current configuration settings.
    /// </summary>
    /// <returns>The behavior extension.</returns>
    protected override object CreateBehavior()
    {
        return new AppFabricE2EEndpointBehavior();
    }

    #endregion BehaviorExtensionElement

}

public class AppFabricE2EEndpointBehavior : IEndpointBehavior //, IServiceBehavior
{

    #region IEndpointBehavior
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) {}


    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        throw new NotImplementedException();
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new AppFabricE2EInspector());

    }

    public void Validate(ServiceEndpoint endpoint)
    {
        ;
    }
    #endregion IEndpointBehavior



}

}

 

 

[1] http://www.microsoft.com/downloads/details.aspx?FamilyID=35ec8682-d5fd-4bc3-a51a-d8ad115a8792&displaylang=en