14

I want to replace the default WCF JSON (for all data types) serialization with JSON.NET. I've searched all over the net and couldn't find a working solution.

This is my object:

    [JsonObject]
public class TestObject
{
    [JsonProperty("JsonNetName")]
    public string Name = "John";

    [JsonProperty]
    public DateTime Date = DateTime.Now;
}

This is my WCF function:

    [OperationContract]
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
    List<TestObject> Get();

This is the code in Global.asax:

        protected void Application_Start(object sender, EventArgs e)
    {
        // Create Json.Net formatter serializing DateTime using the ISO 8601 format
        var serializerSettings = new JsonSerializerSettings();

        serializerSettings.Converters.Add(new IsoDateTimeConverter());
        serializerSettings.Converters.Add(new BinaryConverter());
        serializerSettings.Converters.Add(new JavaScriptDateTimeConverter());
        serializerSettings.Converters.Add(new BinaryConverter());
        serializerSettings.Converters.Add(new StringEnumConverter());

        var config = HttpHostConfiguration.Create().Configuration;

        Microsoft.ApplicationServer.Http.JsonMediaTypeFormatter jsonFormatter = config.OperationHandlerFactory.Formatters.JsonFormatter;

        config.OperationHandlerFactory.Formatters.Remove(jsonFormatter);

        config.OperationHandlerFactory.Formatters.Insert(0, new JsonNetMediaTypeFormatter(serializerSettings));

        var httpServiceFactory = new HttpServiceHostFactory
        {
            OperationHandlerFactory = config.OperationHandlerFactory,
            MessageHandlerFactory = config.MessageHandlerFactory
        };

        //Routing
        RouteTable.Routes.Add(
           new ServiceRoute(
               "Brands", httpServiceFactory,
               typeof(Brands)));

      }

This is Web.Config:

 <endpointBehaviors>
    <behavior name="Behavior_Brands">
      <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Bare" />
    </behavior>
  </endpointBehaviors>

and the services section:

<service name="TestApp.CoreWCF.Brands">
    <endpoint address="" behaviorConfiguration="Behavior_Brands" binding="webHttpBinding" contract="TestApp.CoreWCF.IBrands">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
  </service>

And finally, this is what I'm getting when launching the URL:

"http://localhost:30000/Brands/Get"

[{"Date":"\/Date(1354364412708+0200)\/","Name":"John"}, {"Date":"\/Date(1354364412708+0200)\/","Name":"John"}]

The JSON answer obviously ignores the JSON.NET attributes.

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
max2005b
  • 353
  • 1
  • 2
  • 9

1 Answers1

19

Anyway, I figured out a way to use a different serializer, manually, seems its more efficient and faster because it doesn't pass through Microsoft's serializer, although code wise it's a bit messier.

  1. Set all return types as "System.ServiceModel.Channels.Message" in your Interfaces and classes implementing them.

    [OperationContract]
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
    System.ServiceModel.Channels.Message GetData(); 
    
  2. Create an extension method so you could easily build a memory stream out of an object, using the JSON.NET serializer (or whichever you want to use).

    public static System.ServiceModel.Channels.Message GetJsonStream(this object obj)
    {
        //Serialize JSON.NET
        string jsonSerialized = JsonConvert.SerializeObject(obj);
    
        //Create memory stream
        MemoryStream memoryStream = new MemoryStream(new UTF8Encoding().GetBytes(jsonSerialized));
    
        //Set position to 0
        memoryStream.Position = 0;
    
        //return Message
        return WebOperationContext.Current.CreateStreamResponse(memoryStream, "application/json");
    }
    
  3. In the method's body, return the object serialized directly to the stream

    return yourObject.GetJsonStream();
    
max2005b
  • 353
  • 1
  • 2
  • 9
  • 4
    What are the test results that indicate to you it is definitely faster? Unfortunately for my test case (500KB object hierarchy) using similar alternative techniques, it appears the double step of JSON.NET serialisation _plus_ byte array copying to UTF8 somehow makes it more expensive than just plain DataContractJsonSerializer. :-( – icelava Apr 20 '14 at 10:14