Click or drag to resize
Json.NET

Performance Tips

 

Out of the box Json.NET is faster than DataContractJsonSerializer and JavaScriptSerializer. Here are some tips to make it go even faster.

Reuse Contract Resolver

The IContractResolver resolves .NET types to contracts that are used during serialization inside JsonSerializer. Creating a contract involves inspecting a type with slow reflection, so contracts are typically cached by implementations of IContractResolver like DefaultContractResolver.

To avoid the overhead of recreating contracts every time you use JsonSerializer you should create the contract resolver once and reuse it. Note that if you are not using a contract resolver then a shared internal instance is automatically used when serializing and deserializing.

Reuse ContractResolver
// BAD - a new contract resolver is created each time, forcing slow reflection to be used
string json1 = JsonConvert.SerializeObject(person, new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
});

// GOOD - reuse the contract resolver from a shared location
string json2 = JsonConvert.SerializeObject(person, new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    ContractResolver = AppSettings.SnakeCaseContractResolver
});

// GOOD - an internal contract resolver is used
string json3 = JsonConvert.SerializeObject(person, new JsonSerializerSettings
{
    Formatting = Formatting.Indented
});
Optimize Memory Usage

To keep an application consistently fast, it is important to minimize the amount of time the .NET framework spends performing garbage collection. Allocating too many objects or allocating very large objects can slow down or even halt an application while garbage collection is in progress.

To minimize memory usage and the number of objects allocated, Json.NET supports serializing and deserializing directly to a stream. Reading or writing JSON a piece at a time, instead of having the entire JSON string loaded into memory, is especially important when working with JSON documents greater than 85kb in size to avoid the JSON string ending up in the large object heap.

Deserialize String
HttpClient client = new HttpClient();

// read the json into a string
// string could potentially be very large and cause memory problems
string json = client.GetStringAsync("http://www.test.com/large.json").Result;

Person p = JsonConvert.DeserializeObject<Person>(json);
Deserialize Stream
HttpClient client = new HttpClient();

using (Stream s = client.GetStreamAsync("http://www.test.com/large.json").Result)
using (StreamReader sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
    JsonSerializer serializer = new JsonSerializer();

    // read the json from a stream
    // json size doesn't matter because only a small piece is read at a time from the HTTP request
    Person p = serializer.Deserialize<Person>(reader);
}
JsonConverters

Passing a JsonConverter to SerializeObject or DeserializeObject provides a simple way to completely change how an object is serialized. There is, however, a small amount of overhead; the CanConvert method is called for every value to check whether serialization should be handled by that JsonConverter.

There are a couple of ways to continue to use JsonConverters without any overhead. The simplest way is to specify the JsonConverter using the JsonConverterAttribute. This attribute tells the serializer to always use that converter when serializing and deserializing the type, without the check.

Use JsonConverter with JsonConverterAttribute
[JsonConverter(typeof(PersonConverter))]
public class Person
{
    public Person()
    {
        Likes = new List<string>();
    }

    public string Name { get; set; }
    public IList<string> Likes { get; private set; }
}

If the class you want to convert isn't your own and you're unable to use an attribute, a JsonConverter can still be used by creating your own IContractResolver.

Use JsonConverter with IContractResolver
public class ConverterContractResolver : DefaultContractResolver
{
    public new static readonly ConverterContractResolver Instance = new ConverterContractResolver();

    protected override JsonContract CreateContract(Type objectType)
    {
        JsonContract contract = base.CreateContract(objectType);

        // this will only be called once and then cached
        if (objectType == typeof(DateTime) || objectType == typeof(DateTimeOffset))
        {
            contract.Converter = new JavaScriptDateTimeConverter();
        }

        return contract;
    }
}

The IContractResolver in the example above will set all DateTimes to use the JavaScriptDateConverter.

Manually Serialize

The absolute fastest way to read and write JSON is to use JsonTextReader/JsonTextWriter directly to manually serialize types. Using a reader or writer directly skips any of the overhead from a serializer, such as reflection.

Manually serialize using JsonTextWriter
public static string ToJson(this Person p)
{
    StringWriter sw = new StringWriter();
    JsonTextWriter writer = new JsonTextWriter(sw);

    // {
    writer.WriteStartObject();

    // "name" : "Jerry"
    writer.WritePropertyName("name");
    writer.WriteValue(p.Name);

    // "likes": ["Comedy", "Superman"]
    writer.WritePropertyName("likes");
    writer.WriteStartArray();
    foreach (string like in p.Likes)
    {
        writer.WriteValue(like);
    }
    writer.WriteEndArray();

    // }
    writer.WriteEndObject();

    return sw.ToString();
}

If performance is important and you don't mind writing more code to get it, then this is your best choice. You can read more about using JsonReader/JsonWriter here: Basic Reading and Writing JSON

Benchmarks
performance
See Also