Thursday, December 15, 2011

Working with EndPoint Behavior in WCF

Today I will make a short demo about how you can extend your Wcf service with custom behaviors. Wcf provides many ways of customizing the runtime behavior of your service. For a more detailed explanation please refer to msdn magazine .

First of all, let's find out who the players are. We will be working in the 'ServiceModelLayer' with the 'Dispatcher' in the context of the service host and the 'Proxy' in the context of a client. Their job is to translate between WCF Message Objects and .Net Method Calls.                              

WCF runtime


This pair dispatcher/proxy follow a sequence of steps during which you can insert your own code for message transformation, serialization, parameters inspection and so on.

Here is a list of 'points' where you can plug in and insert your code by implementing the following interfaces.


StageInterceptor InterfaceDescription
Parameter Inspection IParameterInspector Called before and after invocation to
inspect and modify parameter values.
Message Formatting IDispatchMessageFormatter
IClientFormatter
Called to perform serialization and
deserialization.
Message Inspection IDispatchMessageInspector
IClientMessageInspector
Called before send or after receive to
inspect and replace message contents.
Operation Selection IDispatchOperationSelector
IClientOperationSelector
Called to select the operation to invoke for the given message.
Operation Invoker IOperationInvoker Called to invoke the operation.


So now we know what kind of extensions we have and whom they apply to. In order to apply an extension (from the above list) we need to set up a behavior. There are 4 types of behaviors in wcf, each of them sharing this set of methods:
Validate - Called just before the runtime is built—allows you to perform custom validation on the service description.

AddBindingParameters - Called in the first step of building the runtime, before the underlying channel is constructed—allows you to add parameters to influence the underlying channel stack.
ApplyClientBehavior - Allows behavior to inject proxy (client) extensions. Note that this method is not present on IServiceBehavior.
ApplyDispatchBehavior - Allows behavior to inject dispatcher extensions.

One exception is that IServiceBehavior doesn't have an ApplyClientBehavior method because service behaviors can't be applied to clients.

Types of Behaviors


ScopeInterfacePotential Impact
ServiceEndpointContractOperation
ServiceIServiceBehavior
EndpointIEndpointBehavior
ContractIContractBehavior
OperationIOperationBehavior
Let's see now how the behavior and the extension get together.

My example comes from a silverlight application where I had to create a custom behavior in order to catch wcf exceptions. So to achieve this I used  IDispatchMessageInspector to change the status code of the reply to 200 (OK) and the IEndpointBehavior because I wanted to apply this extension only to this level.

Show me some code! :)

Step 1. Create the extension implementing IDispatchMessageInspector

public class SilverlightFaultMessageInspector : IDispatchMessageInspector
{
#region IDispatchMessageInspector Members

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
// Do nothing
return null;
}

public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
if (reply.IsFault)
{
HttpResponseMessageProperty property = new HttpResponseMessageProperty();
// Here the response code is changed to 200.
property.StatusCode = System.Net.HttpStatusCode.OK;
reply.Properties[HttpResponseMessageProperty.Name] = property;
}
}
#endregion
}


Step 2. Create the behavior and apply the entension
public class FaultBehavior : BehaviorExtensionElement, IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}


public void Validate(ServiceEndpoint endpoint)
{
}
public override Type BehaviorType
{
get { return typeof(FaultBehavior); }
}

protected override object CreateBehavior()
{
return new FaultBehavior();
}
#endregion
}


Step 3. Declare the behavior extension in the service config file

Inside the <system.serviceModel> create the <extensions> element if does not exist.

<extensions>
<behaviorExtensions>
  <add name="silverlightFaults" type="myservicename.FaultBehavior, myservicename, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>

NOTE: the type must be the fully qualified name of the assembly/class that you are using and must be declared on a single line, otherwise will not work (WCF known issue)

Step 4. Create an end point behavior and add the extension
<behavior name="myFaultBehavior">
   <silverlightFaults />
 </behavior>

Step 5. Crate an endpoint and assign behavior configuration attribute

<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="MyHttpBinding"
  contract="IMyContract"
behaviorConfiguration="myFaultBehavior">

</endpoint>

And that's it! You can inspect the exceptions that come from a wcf service by using e.Error property in the completed event handler. 

0 comments:

Post a Comment