Friday, July 13, 2012

WCF Extensibility….

The Windows Communication Foundation (WCF) application model is designed to solve the greater part of the communication requirements of any distributed application. But there are always scenarios that the default application model and system-provided implementations do not support. Reasons we can go for extension Parameter Inspection, Message Formatting, Message Inspection, Logging and so on… we can add as many reasons we want this list is also extendable as per requirement… J  In This topic I’ll try to outlines the various areas of extension let’s start by visiting The WCF Pipe line…
The WCF Pipeline…
If we have to brief what is WCF services we can say; Its WCF Messages traveling from server to client or client to server over The WCF Pipeline.

WCF message is primarily represented in SOAP \ XML (WCF POX Messages…) format internally & they can be transferred over the stack in binary or JSON or Plain text format. We can extend WCF Behaviors at service / endpoint / contract / operations. Interface exposed are as follows

1)       IServiceBehavior     3)  IContractBehavior

2)       IEndpointBehavior  4) IOperationBehavior

I’ll show example of Implementation of these Interface while Implementing Message Inspector. Let’s visits Messages Inspectors …

Messages Inspectors
Message Inspectors are most used extension in WCF, they allow inspect, modify, logging, Custom Authentication, Tweaking or replace some message elements in both incoming & out going messages. At Service side Message Inspectors are implemented using IDispatchMessageInspector interface which consist followings
  • AfterReciveRequest
  • BeforeSendReply
Message Inspectors are extended as end point behaviors 
Public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)    {
        dispatchRuntime.MessageInspectors.Add(new MyInspector());
    }
At Client side Message Inspectors are implemented using IClientMessageInspector interface which consist followings
  • BeforeSendRequest
  • AfterReciveReply
It’s added as end point behaviors 
Public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)    {
        clientRuntime.MessageInspectors.Add(new MyInspector());
    }
Implementation of Message Inspector: - (C# Code Sample)
Okay let’s implement Message Inspector end to end... Following is an example of a service-side Message Inspector used to output to the Console any received and sent message:
public class ConsoleOutputMessageInspector : IDispatchMessageInspector
{
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
        request = buffer.CreateMessage();
        Console.WriteLine("Received:\n{0}", buffer.CreateMessage().ToString());
        return null;
    }
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
        reply = buffer.CreateMessage();
        Console.WriteLine("Sending:\n{0}", buffer.CreateMessage().ToString());
    }
} 
In order to configure this message inspector we can extend end point Behavior as follows…
public class ConsoleOutputBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, 
            BindingParameterCollection bindingParameters)
    {
    }
 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, 
              ClientRuntime clientRuntime)
    {
        throw new Exception("Behavior not supported on the consumer side!");
    }
 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
                EndpointDispatcher endpointDispatcher)
    {
        ConsoleOutputMessageInspector inspector = new ConsoleOutputMessageInspector();
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
    }
 
    public void Validate(ServiceEndpoint endpoint)
    {
    }
}
As you can see I implement the IEndpointBehavior interface, which defines three methods (AddBindingParameter, ApplyClientBehavior, and ApplyDispatchBehavior). The one I'm interested on is the ApplyDispatchBehavior that relates to the service-side. This method receives a parameter of type EndpointDispatcher that allows adding custom Message Inspectors instance to the service dispatching environment. Because we're defining an Endpoint Behavior, this behavior affects a single endpoint of a service. To map the behavior to the service endpoint we can use a custom configuration element in the configuration file of the service host. Otherwise we could apply the behavior directly through the Service Host instance. In this sample I used a custom configuration element. To do that we need a custom type describing the configuration element…It is a type inherited from BehaviorExtensionElement, like the following one:
public class ConsoleOutputBehaviorExtensionElement : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new ConsoleOutputBehavior();
    }
 
    public override Type BehaviorType
    {
        get
        {
            return typeof(ConsoleOutputBehavior);
        }
    }
} 
 
The previously declared extension element can be used in the .config file of the service host application as follows :  
<system.serviceModel>
        <services>
            <service name="Service1">
                <endpoint
 
                    behaviorConfiguration="ExntBehavior"
                    address="
http://localhost:8000/ Service1"
                    binding="wsHttpBinding" bindingConfiguration="WsHttpBinding"
                    contract="IService1" />
            </service>   
 
        </services>
        <extensions>
            <behaviorExtensions>
                <add name="consoleOutputBehavior" type="ConsoleOutputBehaviorExtensionElement,Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            </behaviorExtensions>
        </extensions>
        <behaviors>
            <endpointBehaviors>
                <behavior name="ExntBehavior">
                    <consoleOutputBehavior />
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <bindings>
            <wsHttpBinding>
                <binding name="WsHttpBinding">
                    <security mode="None" />
                </binding>
            </wsHttpBinding>
        </bindings>
</system.serviceModel>
So far you have seen how to define custom Message Inspector and how to map it to a single endpoint, using and Endpoint Behavior…
Parameter Inspectors
Parameter Inspectors are similar to Message Inspector but they used CLR object rather than Message object, they allow inspect, modify operations inputs & outputs, Logging & Parameter validation but we can’t modify return value. Parameter Inspectors are implemented using IParameterInspector interface which consist followings
  • BeforeCall
  • AfterCall

Implementation of Parameter Inspectors : - (C# Code Sample)
 Public class NameValidationParameterInspector : IParameterInspector
   {
       readonly int _nameParamIndex;
       const string NameFormat ="[a-zA-Z]";
  
       public NameValidationParameterInspector() : this(0) { }

       public NameValidationParameterInspector(int nameParamIndex)
       {
           _nameParamIndex = nameParamIndex;
       }


       public object BeforeCall(string operationName, object[] inputs)
       {  
           string nameParam = inputs[_nameParamIndex] as string;

           if (nameParam != null)
               if (!Regex.IsMatch(
                   nameParam, NameFormat, RegexOptions.None))
                   throw new FaultException(
                       "Invalid name. Only alphabetical character");
           return null;
       }

       public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState){}
}
Rest we can decide on which Behaviour we want to extend it and then we can modify our configuration, or service attributes as per need.. Implementation would be same as we have done in implementation of Message Inspector….
Though you might not directly need to extend the functionality of WCF it’s nice to know that it’s possible and extremely flexible. The scenario for extending WCF’s functionality might come in handy when you need to apply instrumentation. E.g.: Parameter and Message Inspectors might come in handy for logging every incoming and outgoing parameter and message…
   
Courtesy: Random Web Images, Microsoft .NET 3.5 WCF Book, Several online resources

No comments:

Post a Comment