Replace JSON.NET with Jil JSON serializer in ASP.NET Web API



I have recently come across a comparison of fast JSON serializers in .NET, which shows that Jil JSON serializer is one of the fastest.

Jil is created by Kevin Montrose developer at StackOverlow and it is apparently heavily used by Stackoveflow.

This is only one of many benchmarks you can find on Github project website.

JilSpeed

You can find more benchmarks and the source code at this location https://github.com/kevin-montrose/Jil

In this short article I will cover how to replace default JSON serializer in Web API with Jil.

Create Jil MediaTypeFormatter

First, you need to grab Jil from NuGet

PM> Install-Package Jil

 

 

After that, create JilFormatter using code below.

    public class JilFormatter : MediaTypeFormatter
    {
        private readonly Options _jilOptions;
        public JilFormatter()
        {
            _jilOptions=new Options(dateFormat:DateTimeFormat.ISO8601);
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));

            SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));
            SupportedEncodings.Add(new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true));
        }
        public override bool CanReadType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return true;
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
        {
            var task= Task<object>.Factory.StartNew(() => (this.DeserializeFromStream(type,readStream)));
            return task;
        }


        private object DeserializeFromStream(Type type,Stream readStream)
        {
            try
            {
                using (var reader = new StreamReader(readStream))
                {
                    MethodInfo method = typeof(JSON).GetMethod("Deserialize", new Type[] { typeof(TextReader),typeof(Options) });
                    MethodInfo generic = method.MakeGenericMethod(type);
                    return generic.Invoke(this, new object[]{reader, _jilOptions});
                }
            }
            catch
            {
                return null;
            }

        }


        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, TransportContext transportContext)
        {
            using (TextWriter streamWriter = new StreamWriter(writeStream))
            {
                JSON.Serialize(value, streamWriter, _jilOptions);
                var task = Task.Factory.StartNew(() => writeStream);
                return task;
            }
        }
    }

 

This code uses reflection for deserialization of JSON.

Replace default JSON serializer

In the end, we need to remove default JSON serializer.

Place this code at beginning of WebApiConfig

config.Formatters.RemoveAt(0);
config.Formatters.Insert(0, new JilFormatter());

 

Feel free to test Jil with Web API and don’t forget to subscribe here and don’t miss a new blog post.

 
 

  • Jordan Terrell

    Nice post. Just an observation: You probably don’t want to use Task.Factory.StartNew (or Task.Run). It causes the task to be scheduled on a thread pool thread and, in this case, does the work synchronously on another thread. Better just do the work synchronously and return a completed task using Task.FromResult or TaskCompletionSource, and not incur the overhead of marshaling the work onto another thread.

    There is a great video[1] and article[2] explaining why this is a better approach.

    1: http://channel9.msdn.com/events/TechEd/NorthAmerica/2013/DEV-B318
    2: http://www.infoq.com/articles/Async-API-Design

    • http://blog.developers.ba Radenko Zec

      Hi Jordan. Thanks for a tip. I am not multi-threaded expert. I have just implemented this in usual way all similar formatters are implemented.
      From my point of view if I do all work synchronously maybe it will block current execution thread in case of many concurrent requests.
      Usually job of deserializing data will be finished very fast so Tasks will not live very long.
      I am not sure what is better approach.
      It seams to me to me as if I choose between NodeJs and ASP.NET Web API :)

      • http://zud.io/ markrendle

        The overhead of spinning up a Task on a thread will be worse. For this kind of thing you just want to return Task.FromResult(obj).

        • http://blog.developers.ba Radenko Zec

          Thanks for comment Mark. You are probably right especially because deserialization is not long running task so initialization of Task on a thread is not worth for such a small operation.

  • cgatian

    config.Formatters.RemoveAt(0); seems wrong. What if the built-in isn’t the first formatter?

    • http://blog.developers.ba Radenko Zec

      Thanks for comment.
      You are correct. Usually JSON formatter is on first place. This is just very quick implementation so feel free to adapt code to your needs.

  • icanhasjonas

    There’s a nuget/github JIL formatter at https://github.com/bmbsqd/jil-mediaformatter/ that should be able to do the job

    • http://blog.developers.ba Radenko Zec

      Hi Jonas.
      Thanks for creating the project.
      It is always nice to have Nuget package at hand.

  • http://www.dj4life.co.za/ Quinton

    Looks awesome, but sadly my project can only run in 4.0 for the next while, so can’t make use of Jil yet

    • http://blog.developers.ba Radenko Zec

      Quinton thanks for comment.
      Sorry for hear that. Better luck on your next project.
      Don’t forget to subscribe to this blog http://eepurl.com/ZfI8v and make sure you don’t miss upcoming blog posts.

      • http://www.dj4life.co.za/ Quinton

        Thanks for the subscription link, subscribed