by Keyvan Nayyeri via Keyvan Nayyeri on 2/23/2009 6:14:11 PM
In one of my recent blog posts I talked about IOperationBehavior interface as an extensibility point to customize operation behavior in Windows Communication Foundation. There I pointed that this interface works in conjunction with various options in WCF to expand the existing features on service and/or client side. In this post I’m going to cover one of these extensibility points.
As I said in that post, one of the most notable points about WCF is the level of customizability that it offers for all its elements. One of the basic elements in WCF functioning is message which is the data that is being transferred between client and server in order to enable the communication of data. The default implementation of WCF behaviors offers a built-in structure for messages, but there may be many circumstances where you need to have a custom structure for your messages on client or service side or both.
IDispatchMessageFormatter and IClientMessageFormatter are two interfaces that offer the capability of customizing messages on service and client sides in WCF respectively. Both these interfaces have the very similar methods and structures and work in the same way. IDispatchMessageFormatter works on service-side and IClientMessageFormatter works on the client-side.
IDispatchMessageFormatter provides the following two methods:
IClientMessageFormatter has a very similar structure where methods act in the same way with appropriate naming:
As these two interfaces are very similar, here I concentrate on IDispatchMessageFormatter to write a sample.
First I create a service with the following contract.
using System.ServiceModel;
namespace IDispatchMessageFormatterSample
{
[ServiceContract]
public interface ISampleService
[OperationContract]
[SampleOperationBehavior]
string GetData(string id);
}
Later you will see the implementation of SampleOperaitonBehavior which is a custom operation behavior that I talked about its role before. The single method for this service is also presented below.
public class SampleService : ISampleService
#region ISampleService Members
public string GetData(string id)
return string.Format("Your id is {0}.", id);
#endregion
Now I write my implementation of I IDispatchMessageFormatter interface.
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Xml;
public class MessageFormatter : IDispatchMessageFormatter
#region IDispatchMessageFormatter Members
public void DeserializeRequest(Message message, object[] parameters)
XmlDictionaryReader reader = message.GetReaderAtBodyContents();
reader.MoveToContent();
if (reader.Read())
string value = reader.ReadContentAsString();
parameters[0] = value;
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
Message message = Message.CreateMessage(messageVersion,
"http://tempuri.org/ISampleService/GetDataResponse",
result);
return message;
Here in DeserializeRequest method I parse the body section of incoming message and extract the single id parameter from the XML data to add it to the array of parameters. You may need to know the XML structure of incoming message to understand how it works, so here it is:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/ISampleService/GetData</a:Action>
<a:MessageID>urn:uuid:5e780280-7924-45c0-a400-5c6908b52676</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
<s:Body>
<GetData xmlns="http://tempuri.org/">
<id>6</id>
</GetData>
</s:Body>
</s:Envelope>
The other method in my implementation is SerializeReply where I build and return my own Message object as the response. I didn’t add much customization to my Message object but still you can notice the difference in the generated XML response in the end of this post.
The last piece of this service is where I implement my custom operation behavior from IOperationBehavior.
using System;
using System.ServiceModel.Description;
public class SampleOperationBehavior : Attribute, IOperationBehavior
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
dispatchOperation.Formatter = new MessageFormatter();
public void Validate(OperationDescription operationDescription)
As I said in my previous post, I can use ApplyDispatchBehavior method in order to customize the operation behavior on service-side. All I need is setting the Formatter property of DispatchOperation to an instance of my custom message formatter class in order to replace the default formatter implementation. I had noted that the main application of IOperationBehavior can be seen when it works with other extensibility points, and now you can see it.
To notice the difference between the default response XML structure returned from the service and the new one (after applying my custom formatter), first take a look at the default XML.
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<a:Action s:mustUnderstand="1" u:Id="_2">http://tempuri.org/ISampleService/GetDataResponse</a:Action>
<a:RelatesTo u:Id="_3">urn:uuid:7fc59467-5fa9-402c-a619-42c7942333ff</a:RelatesTo>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="uuid-250e61ac-70c2-4647-a008-256973dc5e54-11">
<u:Created>2009-02-23T18:01:42.413Z</u:Created>
<u:Expires>2009-02-23T18:06:42.413Z</u:Expires>
</u:Timestamp>
<c:DerivedKeyToken u:Id="uuid-250e61ac-70c2-4647-a008-256973dc5e54-7" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference URI="urn:uuid:8376faec-61d9-4fed-8d6e-2a2cf95b6a13" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
</o:SecurityTokenReference>
<c:Offset>0</c:Offset>
<c:Length>24</c:Length>
<c:Nonce>az8CB4WhYhqGhEkPnZONig==</c:Nonce>
</c:DerivedKeyToken>
<c:DerivedKeyToken u:Id="uuid-250e61ac-70c2-4647-a008-256973dc5e54-8" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<c:Nonce>gV+TTYqKC8RPGiO/abAgWg==</c:Nonce>
<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:DataReference URI="#_1" />
<e:DataReference URI="#_4" />
</e:ReferenceList>
<e:EncryptedData Id="_4" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" URI="#uuid-250e61ac-70c2-4647-a008-256973dc5e54-8" />
</KeyInfo>
<e:CipherData>
<e:CipherValue>8pa91GqYTowd8NGHX</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</o:Security>
<s:Body u:Id="_0">
<GetDataResponse xmlns="http://tempuri.org/">
<GetDataResult>Your id is 6.</GetDataResult>
</GetDataResponse>
Now compare it with the new XML content after applying the new formatter.
<a:Action s:mustUnderstand="1">http://tempuri.org/ISampleService/GetDataResponse</a:Action>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Your id is 6.</string>
The source code sample for this post is available here.
+ I guess that this post is one of the blog posts that finds its audience in the future!
Original Post: Use IDispatchMessageFormatter and IClientMessageFormatter to Customize Messages in WCF
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.