unity Newtonsoft JSON.NET compatibility with Json web services




web api use newtonsoft json (4)

I've been searching for ways to use JSON.NET to handle JSON serialization. The best approach that I've found is to create a WCF behavior extension by deriving from BehaviorExtensionElement class. It is described here:

http://json.codeplex.com/discussions/209865

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public class JsonNetBehaviorExtension : BehaviorExtensionElement
{
    public class JsonNetBehavior : WebHttpBehavior
    {
        internal class MessageFormatter : IDispatchMessageFormatter
        {
            JsonSerializer serializer = null;
            internal MessageFormatter()
            {
                serializer = new JsonSerializer();
            }

            public void DeserializeRequest(Message message, object[] parameters)
            {
                throw new NotImplementedException();
            }

            public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
            {
                var stream = new MemoryStream();
                var streamWriter = new StreamWriter(stream, Encoding.UTF8);
                var jtw = new JsonTextWriter(streamWriter);
                serializer.Serialize(jtw, result);
                jtw.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                return WebOperationContext.Current.CreateStreamResponse(stream, "application/json");
            }
        }

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

    public JsonNetBehaviorExtension() { }

    public override Type BehaviorType
    {
        get
        {
            return typeof(JsonNetBehavior);
        }
    }

    protected override object CreateBehavior()
    {
        var behavior = new JsonNetBehavior();
        behavior.DefaultBodyStyle = WebMessageBodyStyle.WrappedRequest;
        behavior.DefaultOutgoingResponseFormat = WebMessageFormat.Json;
        behavior.AutomaticFormatSelectionEnabled = false;
        return behavior;
    }
}

Then in your web.config

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="webHttpJson" type="YourNamespace.JsonNetBehaviorExtension, YourAssembly"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <endpointBehaviors>
        <behavior name="NewtonsoftJsonBehavior">
          <webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
          <webHttpJson/>
        </behavior>
      </endpointBehaviors>
     <behaviors>

I was wondering since I didn't find it anywhere -

Can a Json based web service be used in conjunction with the Json.NET library?

In other words, is there a way to make JSON.NET deserialize the webservice's request's JSON object instead of .NET default Serializer?

One way to do it is probably declare the WebMethod to accept a plain string, and then use JSON.NET's JsonConvert, to deserialize that raw string into the correct object, but that means that the request's syntax (from the client side) will be kind of awkward.

Is there any other ways or suggestions of doing this?

Thanks,

Mikey


AFAIK, you have to do this manually, by having your web service take a string as argument and return a string as response. If you use WCF things are much different as the architecture is much more extensible in comparison to classic ASMX web services which by the way are considered a deprecated technology now.


How to set Json.Net as the default serializer for WCF REST service

The usage of Extending Encoders and Serializers (see http://msdn.microsoft.com/en-us/library/ms733092.aspx) or other methods of Extending WCF like usage of DataContractSerializerOperationBehavior is very interesting, but for your special problem there are easier solution ways.

If you already use Message type to return the results an use WCF4 you can do something like following:

public Message UpdateCity(string code, City city)
{
    MyResponseDataClass message = CreateMyResponse();
    // use JSON.NET to serialize the response data
    string myResponseBody = JsonConvert.Serialize(message);
    return WebOperationContext.Current.CreateTextResponse (myResponseBody,
                "application/json; charset=utf-8",
                Encoding.UTF8);
}

In case of errors (like HttpStatusCode.Unauthorized or HttpStatusCode.Conflict) or in other situations when you need to set a HTTP status code (like HttpStatusCode.Created) you can continue to use WebOperationContext.Current.OutgoingResponse.StatusCode.

As an alternative you can also return a Stream (see http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx and http://msdn.microsoft.com/en-us/library/ms732038.aspx) instead of Message to return any data without additional default processing by Microsoft JSON serializer. In case of WCF4 you can use CreateStreamResponse (see http://msdn.microsoft.com/en-us/library/dd782273.aspx) instead of CreateTextResponse. Don't forget to set stream position to 0 after writing in the stream if you will use this technique to produce the response.


Is there some reason why you want to use the Json.NET library specifically. If you want to return JSON, why not just use the ResponseFormat property from the WebGet and WebInvoke attributes?

[WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]

That should for most cases. What version of WCF are you running? Any reason you're returning a Message type rather than the actual type?