Pages

Thursday, November 18, 2010

Analyzing communication to CRM 2011–Analyzing WCF messages

One of the technical news in Dynamics CRM 2011 is the use of WCF-based web services instead of the old ASP.NET based web services.
Now let me say one thing about WCF. It is far to complex. Personally I think this was made in order to demonstrate that Microsoft can create really complex frameworks.
But the nice thing is that behind this complexity the framework is also very flexible, you just have to know where to hook into.
So the problem I had was that I called a web service on the new Organization.svc endpoint and got the fault that the server was not able to de-serialize the message, as it was in a wrong format.
My first step analyzing such an error is looking at the actual xml that was send to the server. Starting up Fiddler I realized that the new endpoint is now using WS-Security to encrypt the message content, thus logging the traffic was not very helpful.
So I decided to hook into WCF in order to log the actual message before it is encrypted.
You can modify WCF by adding behaviors to it. In order to do that for CRM, you have to add a behavior to the Service Endpoint of the service configuration.
You have to do that before you instantiate the OrganizationService with the ServiceConfiguration.
In order to be able to reuse that I implemented that as an Extension Method to IServiceConfiguration like this:
public static IServiceConfiguration<IOrganizationService> ApplyMessageInspector(this IServiceConfiguration<IOrganizationService> orgCfg)
{
  orgCfg.CurrentServiceEndpoint.Behaviors.Add(new MessageInspectorBehaviour());
  return orgCfg;
}

I want to add a client behavior, so I implemented ApplyClientBehavoir
public class MessageInspectorBehaviour : IEndpointBehavior
{
  public void Validate(ServiceEndpoint endpoint)
  {
  }

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

  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
  {
  }

  public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
    clientRuntime.MessageInspectors.Add(new MessageInspector());
  }
}

A message inspector allows you to inspect and also modify the message if you want. In my case I only wanted to send the messages in my request and the servers response to my favorite logging tool NLog:
public class MessageInspector : IClientMessageInspector
{

  private static readonly Logger ReqLogger = LogManager.GetLogger("WCF.Client.Request");
  private static readonly Logger ResLogger = LogManager.GetLogger("WCF.Client.Response");


  public object BeforeSendRequest(ref Message request, IClientChannel channel)
  {
    ReqLogger.Info(request);
    return null;
  }

  public void AfterReceiveReply(ref Message reply, object correlationState)
  {
    ResLogger.Info(reply);
  }
}

So that’s it, quite easy if you already have the code, but if you have to dig around the API first a big pain.

No comments:

Post a Comment