Using a WCF Message Inspector to extend AppFabric Monitoring
- by Shawn Cicoria
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: IDispatchMessageInspector implementation BehaviorExtensionElement implementation 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