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)
        {
	        return Task.FromResult(this.DeserializeFromStream(type, readStream));           
        }


        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)
        {
            var streamWriter = new StreamWriter(writeStream);
            JSON.Serialize(value, streamWriter, _jilOptions);
            streamWriter.Flush();
            return Task.FromResult(writeStream);
        }
    }

 

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.

 

30 Comments on Replace JSON.NET with Jil JSON serializer in ASP.NET Web API

  1. Jordan Terrell
    July 22, 2014 at 2:21 pm (10 years ago)

    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

    Reply
    • Radenko Zec
      July 22, 2014 at 8:02 pm (10 years ago)

      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 🙂

      Reply
      • markrendle
        July 23, 2014 at 10:17 am (10 years ago)

        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).

        Reply
        • Radenko Zec
          July 23, 2014 at 10:43 am (10 years ago)

          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.

          Reply
          • dotnetchris
            October 7, 2014 at 3:06 pm (10 years ago)

            It would be nice for to modify your post to use this incase future readers copy and paste this.

          • Radenko Zec
            October 7, 2014 at 6:56 pm (10 years ago)

            I have just updated code in this blog post implementing improvements suggested in this comment.

          • dotnetchris
            October 7, 2014 at 7:04 pm (10 years ago)

            Should this also be applied to WriteToStreamAsync? I’m not really sure what’s going on with calling StartNew and handing it a stream, I would suspect that the work has already been completed synchronously by JSON.Serialize()… unless that method is lazy and will only execute when the Stream is read?

          • Radenko Zec
            October 7, 2014 at 7:12 pm (10 years ago)

            Sorry. I have missed that.
            I have implemented a same approach on WriteToStreamAsync.

    • Paul Kim
      December 23, 2019 at 7:29 pm (4 years ago)

      I also think that Jil is a bit premature even today as it lacks support. I’ve recently tried to integrate Jil into my project and ended up reverting back to Newtonsoft because I faced issues in serializing/deserializing JSON with DateTime fields..

      Reply
  2. cgatian
    July 22, 2014 at 4:56 pm (10 years ago)

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

    Reply
    • Radenko Zec
      July 22, 2014 at 7:35 pm (10 years ago)

      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.

      Reply
    • Radenko Zec
      July 24, 2014 at 5:41 am (10 years ago)

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

      Reply
  3. Quinton
    July 24, 2014 at 6:07 am (10 years ago)

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

    Reply
    • Radenko Zec
      July 24, 2014 at 6:12 am (10 years ago)

      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.

      Reply
      • Quinton
        July 24, 2014 at 6:46 am (10 years ago)

        Thanks for the subscription link, subscribed

        Reply
    • dotnetchris
      October 7, 2014 at 3:02 pm (10 years ago)

      ” but sadly my project can only run in 4.0 for the next while”

      Who gets to make these stupid decisions? Unless it’s a redistributable application/assemblies that you don’t want to preclude customers from, there’s literally zero reasons to not use 4.5 over 4.0.

      Reply
      • Quinton Viljoen
        October 8, 2014 at 6:38 am (10 years ago)

        We host the application in our data center for multiple large customers, using server 2008. IIS on 2008 doesn’t just plug 4.5 out of the box, so there is a bit of a upgrade that has to take place before we can just recompile for 4.5…

        The project stakeholders say the risk outweighs the benefits of going 4.5 just yet and would rather go that route once we upgrade to server 2012.

        Reply
        • dotnetchris
          October 8, 2014 at 12:58 pm (10 years ago)

          Server 2008 as opposed 2008 R2 that is?

          Reply
  4. dotnetchris
    October 7, 2014 at 3:06 pm (10 years ago)

    MethodInfo method = typeof(JSON).GetMethod(“Deserialize”, new Type[] { typeof(TextReader),typeof(Options) });
    MethodInfo generic = method.MakeGenericMethod(type);

    You might want to make these static readonly fields. I can’t say for sure it would be beneficial, i never know off hand what reflection things do all the right caching for you themselves but this is definitely one that would never vary and could easily be a static field. Since it’s all compile time constants and typeofs.

    Reply
    • Radenko Zec
      October 7, 2014 at 6:41 pm (10 years ago)

      Hey Chris.
      Thanks for advice. You are absolutely right.
      It’s something that Resharper will also probably recommend. However I haven’t got time to improve this code after initial blog post.
      I will try to do this in near future.

      Reply
  5. kamerrer
    October 15, 2014 at 2:50 pm (10 years ago)

    How to config JilFormatter to camel case like this:

    var jsonFormatter = config.Formatters.OfType().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

    Reply
    • Radenko Zec
      October 16, 2014 at 6:06 am (10 years ago)

      Hi kamerrer. Unfortunately, I don’s see a way to force Jil to serialize using camel case.
      Currently this option is not available in Jil serializer.
      Jil supports customizable names (via [DataMember] and [JilDirective]), but then you will need to manually decorate all properties of classes.
      Read this explanation here : https://github.com/kevin-montrose/Jil/issues/35

      Reply
      • Waqas Usman
        February 3, 2016 at 12:35 am (8 years ago)

        Hi Radenko,

        First of all thank you for this blog, it was very helpful!

        You may already have noticed, the camelCase serialization is now supported and it is mentioned on the github page you linked to. You can do it by adding the SerializationNameFormat in Options like this:

        _jilOptions = new Options(dateFormat: DateTimeFormat.MillisecondsSinceUnixEpoch, serializationNameFormat:SerializationNameFormat.CamelCase);

        Reply
  6. Guy
    January 13, 2016 at 11:44 am (8 years ago)

    Does any one know if Jil can accept ContentType : json in the http call to the API ?
    From what I see it can only accept ContentType:x-www-formencoded

    Reply
  7. Amit
    May 16, 2016 at 11:42 am (8 years ago)

    It is not working in case of enum. When I try to pass enum to Web Api then it throw exception at Expected character: ‘”‘ in DeserializeFromStream method . this is my Json {"device_id":"1233","device_type":1} here device_type is enum

    Reply
  8. Aniket Bhansali
    January 9, 2017 at 12:01 pm (7 years ago)

    I keep getting following error, *Error occurred building a deserializer for HotelFirst.Models.tblHotelTax: Member [Connection] isn’t marked as part of a union, but other members share the same Name [Connection]* whenever I make POST request to web-api.

    Reply
  9. Simon
    March 28, 2018 at 7:09 am (6 years ago)

    I get this error “the best overloaded method match for System.Convert.FromBase64String(string) has some invalid arguments” when trying to retrieve a base64 string using Jil?

    Reply
  10. salem albadawi
    August 22, 2018 at 2:30 pm (6 years ago)

    Type ‘Rct.Entity.RctResponse`1[Rct.Entity.Model.Company]’ cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.

    Reply
  11. Armin Zia
    November 3, 2018 at 2:20 am (5 years ago)

    Hey Radenko, thanks for the post. I wanna give Jil a try but I’m afraid it won’t satisfy my requirements because I have some configuration on the NewtonSoft.Json library. How can I achieve the same thing with Jil or another (faster) library?

    var formatter = config.Formatters.JsonFormatter;
    formatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
    formatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
    formatter.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat;
    formatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

    Many thanks

    Reply

Leave a Reply