[Source: http://geekswithblogs.net/EltonStoneman]
The WCF message formatter interfaces IClientMessageFormatter and IDispatchMessageFormatter let you intercept WCF messages on the client or service side at the point of serialization and deserialization. They’re useful injection points as they give you access to the input or output parameter values of the service call, and to the incoming or outgoing WCF Message object. The formatters allow you to inspect or modify the message content or headers, using the call parameters to drive your logic.
Formatters need to be applied as operation behaviors, so there’s no direct way to add them via binding configurations – typically they’re added programmatically to the client channel, or to the service as attributes on the operation contract. But if your requirements are to add the same formatter to every operation and you want the flexibility of the configuration model, you can add formatters by piggybacking onto other behaviors which can be specified in configuration – IEndpointBehavior on the client and IServiceBehavior on the service:
(more detail on the data signature project in a future post).
Client Side
DataSignatureOperationBehavior.ApplyClientBehavior adds a DataSignatureClientFormatter to a single client operation:
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
DataSignatureClientFormatter formatter = new DataSignatureClientFormatter();
formatter.OrginalFormatter = clientOperation.Formatter;
clientOperation.Formatter = formatter;
}
Adding the formatter to one operation cannot be specified in client-side configuration. However the DataSignatureOperationBehavior can be added to every client operation in an endpoint using IEndpointBehavior.ApplyClientBehavior. DataSignatureEndpointBehavior adds the client formatter to every operation, by using the existing operation behavior:
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
operation.Behaviors.Add(new DataSignatureOperationBehavior());
}
}
The endpoint behavior is exposed in the client configuration mode by extending BehaviorExtensionElement, so the DataSignatureFormatter can be added to every operation in an endpoint by configuring the DataSignatureEndpointBehavior:
<client>
<endpoint address=“http://localhost/x.y.z.svc”
binding=“basicHttpBinding“ bindingConfiguration=“BasicHttpBinding_ICustomerService“
behaviorConfiguration=“dataSignatureBehavior“
contract=“CustomerService.ICustomerService“ name=“BasicHttpBinding_ICustomerService“ />
</client>
<behaviors>
<endpointBehaviors>
<behavior name=“dataSignatureBehavior“>
<dataSignatureBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add
name=“dataSignatureBehavior”
type=“Sixeyed.OptimisticLockingSample.ServiceModel.Behaviors.DataSignatureEndpointBehavior/>
</behaviorExtensions>
</extensions>
Service Side
The service stack is the parallel of the client side – DataSignatureDispatchFormatter is added via an operation behavior using DataSignatureOperationBehavior.ApplyDispatchBehavior:
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
DataSignatureDispatchFormatter formatter = new DataSignatureDispatchFormatter();
formatter.OrginalFormatter = dispatchOperation.Formatter;
dispatchOperation.Formatter = formatter;
}
Again this behavior is not available in the service configuration model, but it can be added to every operation in the service using IServiceBehavior.ApplyDispatchBehavior, as is done in DataSignatureServiceBehavior:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
operation.Behaviors.Add(new DataSignatureOperationBehavior());
}
}
}
This behavior also extends BehaviorExtensionElement so it can be configured, adding the dispatch formatter will be added to every operation in the service:
<services>
<service behaviorConfiguration=“dataSignatureBehavior”
name=“Sixeyed.OptimisticLockingSample.Services.CustomerService“>
<endpoint address=“” binding=“basicHttpBinding“ contract=“Sixeyed.OptimisticLockingSample.Services.ICustomerService”
bindingNamespace=“http://Sixeyed.OptimisticLockingSample/2009“/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name=“ dataSignatureBehavior “>
<serviceMetadata httpGetEnabled=“true“/>
<serviceDebug includeExceptionDetailInFaults=“true“/>
<dataSignatureBehavior/>>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add
name=“dataSignatureBehavior”
type=“Sixeyed.OptimisticLockingSample.ServiceModel.Behaviors.DataSignatureServiceBehavior/>
</behaviorExtensions>
</extensions>
Additionally, the DataSignatureOperationBehavior extends Attribute, so for finer-grained control the declarative approach is available using the same stack.