Replacing WCF DataContractJsonSerializer with Newtonsoft JsonSerializer

Have you ever had the need to customize json serialization and deserialization of your WCF rest endpoint? I have, in particular to replace the WCF datetime format by generalized time format. By default, most json serializers serialize datetime objects to a generalized time format, this could lead to problems if you are creating a WCF rest endpoint which only supports input of microsofts datetime implementation like this \/Date(1293034567877)\/. A way to solve this problem is to replace the behavior of your rest endpoint by a custom one that uses newtonsofts json serializer instead.

To do this we have to create a message formatter class by implementing IDispatchMessageFormatter:

public class NewtonsoftJsonDispatchFormatter : IDispatchMessageFormatter  
{
    public void DeserializeRequest( Message message, object[] parameters ) { ... }
    public Message SerializeReply( MessageVersion messageVersion, object[] parameters, object result ) { ... }
}

This class will be using newtonsofts json serializer to serialize and deserialize messages. Next we have to create a behavior class that extends WebHttpBehavior:

public class NewtonsoftJsonBehavior : WebHttpBehavior  
{
    protected override IDispatchMessageFormatter GetRequestDispatchFormatter( OperationDescription operationDescription, ServiceEndpoint endpoint )
    {
        return new NewtonsoftJsonDispatchFormatter( operationDescription, true );
    }

    protected override IDispatchMessageFormatter GetReplyDispatchFormatter( OperationDescription operationDescription, ServiceEndpoint endpoint )
    {
        return new NewtonsoftJsonDispatchFormatter( operationDescription, false );
    }
}

The only thing left to do is tell the WCF endpoint to use this new behavior. One way to do that is using your web.config to connect the new behavior to your endpoint. In order to do that we have to create a behavior extension class by extending the BehaviorExtensionElement class:

public class NewtonsoftJsonBehaviorExtension : BehaviorExtensionElement  
{
    public override Type BehaviorType
    {
        get { return typeof( NewtonsoftJsonBehavior ); }
    }

    protected override object CreateBehavior()
    {
        return new NewtonsoftJsonBehavior();
    }
}

And create a content type mapper:

public class NewtonsoftJsonContentTypeMapper : WebContentTypeMapper  
{
    public override WebContentFormat GetMessageFormatForContentType( string contentType )
    {
        return WebContentFormat.Raw;
    }
}

Now when configuring your binding you can simply setup an extension like this:

<extensions>  
  <behaviorExtensions>
    <add name="newtonsoftJsonBehavior" type="MyApp.NameSpace.NewtonsoftJsonBehaviorExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>

Setup your enpoint behavior like this:

<endpointBehaviors>  
  <behavior name="restEndPointBehavior">
    <webHttp helpEnabled="false" defaultBodyStyle="Bare" defaultOutgoingResponseFormat="Json" faultExceptionEnabled="false" />
    <newtonsoftJsonBehavior/>
  </behavior>
</endpointBehaviors>

Configure a webHttpBinding to use our custom contentTypeMapper:

<bindings>  
  <webHttpBinding>
    <binding name="restWebHttpBinding" contentTypeMapper="MyApp.NameSpace.NewtonsoftJsonContentTypeMapper, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  </webHttpBinding>
</bindings>

And finally setting up our endpoint like this:

<services>  
  <service name="MyApp.NameSpace.Service" behaviorConfiguration="restServiceBehavior">
    <endpoint address="" behaviorConfiguration="restEndPointBehavior" binding="webHttpBinding" bindingConfiguration="restWebHttpBinding" contract="MyApp.NameSpace.IService" />
  </service>
</services>

Your WCF rest endpoint is now using your own message formatter to serialize and deserialize messages! There are some other cool features when using newtonsofts json serializer. For example if your service method has a byte[] parameter, you can just post a Base64 encoded string and it will be automatically deserialized to a byte[] on the server.

Check out the full source at GitHub.