-
Notifications
You must be signed in to change notification settings - Fork 18
Custom Formatters Overview
Custom formatters can be created to de/serialize requests/responses. These formatters implement the WcfRestContrib.ServiceModel.Dispatcher.IWebFormatter interface:
public interface IWebFormatter { object Deserialize(WebFormatterDeserializationContext context, Type type); WebFormatterSerializationContext Serialize(object data, Type type); }
Deserialize Method
The first method you will need to implement is the Deserialize method. The web dispatch formatter passes in a deserialization context and the type that the entity body should be deserialized to. The WebFormatterDeserializationContext specifies the format of the entity body in the ContentFormat property; either “Binary” or “Xml”. “Binary” simply means that it is not xml, so this includes text. If the content format is binary you will get the entity body from the BinaryData property of the deserialization context. If it is xml you will get the entity body from the XmlReader property. Your formatter should always pull from one or the other depending on the format of the data your formatter expects. If your formatter expects xml and the entity body is binary you can throw an exception indicating an invalid entity body format. Once the entity body is deserialized the new object is returned.
The following demonstrates how to implement the deserialize method:
public class FormUrlEncoded : IWebFormatter { public object Deserialize(WebFormatterDeserializationContext context, Type type) { if (context.ContentFormat == WebFormatterDeserializationContext.DeserializationFormat.Binary) { FormUrlEncodedReader formReader = new FormUrlEncodedReader(new MemoryStream(context.BinaryData)); DataContractSerializer serializer = new DataContractSerializer(type); return serializer.ReadObject(formReader, false); } else throw new InvalidDataException("Data must be in binary format."); } ... }
Serialize Method
The next method you will need to implement is the Serialize method. The object to be serialized and its type are passed in. A WebFormatterSerializationContext object is returned. To create this object use the static methods on this class; CreateBinary or CreateXmlSerialized. Again, “Binary” is anything that is not xml which includes plain text. The CreateBinary method accepts a byte array while the CreateXmlSerialized accepts an XmlObjectSerializer.
The following demonstrates how to implement the serialize method:
public class FormUrlEncoded : IWebFormatter { public WebFormatterSerializationContext Serialize(object data, Type type) { MemoryStream stream = new MemoryStream(); DataContractSerializer serializer = new DataContractSerializer(type); serializer.WriteObject(new FormUrlEncodedWriter(stream), data); stream.Position = 0; return WebFormatterSerializationContext.CreateBinary( new BinaryReader(stream).ReadBytes((int)stream.Length)); } ... }
Registering
Once you’ve created your custom formatter you will need to register it on your service declaratively:
[WebDispatchFormatterConfiguration("text/yada")] [WebDispatchFormatterMimeType(typeof(MyCustomFormatter), "text/yada")] ... public class MyService : IMyService {...}
Or in configuration:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="webFormatter" type="WcfRestContrib.ServiceModel.Configuration.WebDispatchFormatter.ConfigurationBehaviorElement, WcfRestContrib, Version=x.x.x.x, Culture=neutral, PublicKeyToken=89183999a8dc93b5"/> </behaviorExtensions> </extensions> <behaviors> <serviceBehaviors> <behavior name="Rest"> <webFormatter> <formatters defaultMimeType="text/yada"> <formatter mimeTypes="text/yada" type="MyCustomFormatter, MyAssembly"/> ... </formatters> </webFormatter> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Once the formatter has been configured on the service the WcfRestContrib.ServiceModel.Description.WebDispatchFormatterAttribute can be applied to operations where automatic formatting is desired:
[ServiceContract] public interface IMyService { [WebInvoke(UriTemplate = "/{id}", Method=Verbs.Post)] [WebDispatchFormatter] [OperationContract] Foo DoSomething(string id, Bar bar); .... }
NOTE: The WcfRestContrib.ServiceModel.Web.WebServiceHost allows you to specify configuration based behaviors if you do not want to specify this declaratively. See more about it under Declarative Binding & Behavior Overview.