Comparative Performance Analysis of JSON Serialization in .NET

Object serialization is a fundamental requirement in modern software development, particularly for data transmission and storage. In the .NET ecosystem, developers often choose between built-in libraries and third-party solutions. This analysis benchmarks three common approaches: JavaScriptSerializer, DataContractJsonSerializer, and the widely adopted Newtonsoft.Json (Json.NET) library. We will examine their efficiency in handling both strongly typed objects and loosely typed DataTable structures.

1. Library Dependencies and Setup

Before implementing the benchmark, ensure the necessary namespaces and assemblies are referenced in your project.

  • JavaScriptSerializer: Located in System.Web.Script.Serialization. Requires a reference to System.Web.Extensions.dll.
  • DataContractJsonSerializer: Part of System.Runtime.Serialization.Json. Requires a reference to System.Runtime.Serialization.dll.
  • Newtonsoft.Json: A third-party library available via NuGet. Its the industry standard for JSON handling in .NET.

2. Serialization Helper Implementation

To standardize the testing process, wrapper methods have been created for the native .NET serializers. The code below refactors the logic into cleaner extension methods.

using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web.Script.Serialization;

public static class SerializationExtensions
{
    // DataContractJsonSerializer Wrappers
    public static string ToDataContractJson<T>(this T obj)
    {
        try
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream())
            {
                serializer.WriteObject(ms, obj);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }
        catch
        {
            return string.Empty;
        }
    }

    public static T FromDataContractJson<T>(this string json)
    {
        try
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                return (T)serializer.ReadObject(ms);
            }
        }
        catch
        {
            return default(T);
        }
    }

    // JavaScriptSerializer Wrappers
    public static string ToLegacyJson<T>(this T obj)
    {
        try
        {
            var serializer = new JavaScriptSerializer();
            return serializer.Serialize(obj);
        }
        catch
        {
            return string.Empty;
        }
    }

    public static T FromLegacyJson<T>(this string json)
    {
        try
        {
            var serializer = new JavaScriptSerializer();
            return serializer.Deserialize<T>(json);
        }
        catch
        {
            return default(T);
        }
    }
}

For Newtonsoft.Json, the native static methods JsonConvert.SerializeObject and JsonConvert.DeserializeObject are used directly without custom wrappers.

3. Test Data Generation

The benchmark utilizes two data sources: a collection of strongly typed objects and a DataTable. The methods below generate the test datasets.

using System;
using System.Collections.Generic;
using System.Data;

public class DataFactory
{
    public static List<User> GenerateUserList(int count)
    {
        var list = new List<User>();
        for (int i = 0; i < count; i++)
        {
            list.Add(new User
            {
                Name = "User_" + i,
                Age = 20 + (i % 10),
                IsActive = i % 5 == 0,
                FieldA = i.ToString(),
                FieldB = i.ToString(),
                FieldC = i.ToString()
                // Additional properties omitted for brevity
            });
        }
        return list;
    }

    public static DataTable GenerateDataTable(int count)
    {
        var table = new DataTable("SampleTable");
        table.Columns.Add("ID", typeof(int));
        table.Columns.Add("FullName", typeof(string));
        table.Columns.Add("Role", typeof(string));
        
        for (int i = 0; i < count; i++)
        {
            var row = table.NewRow();
            row["ID"] = i + 1;
            row["FullName"] = "Name" + i;
            row["Role"] = i % 2 == 0 ? "Admin" : "User";
            table.Rows.Add(row);
        }
        return table;
    }
}

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public bool IsActive { get; set; }
    public string FieldA { get; set; }
    public string FieldB { get; set; }
    public string FieldC { get; set; }
}

4. Benchmark Execution Logic

The following code implements the performance test using System.Diagnostics.Stopwatch to measure execution time for both serialization and deserialization operations on a large dataset.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Newtonsoft.Json;

class Program
{
    static void Main(string[] args)
    {
        const int itemCount = 50000;
        var sourceData = DataFactory.GenerateUserList(itemCount);
        
        Console.WriteLine($"--- Testing Strongly Typed Objects (Count: {itemCount}) ---\n");

        // Test 1: JavaScriptSerializer
        RunBenchmark("JavaScriptSerializer", sourceData, 
            data => data.ToLegacyJson(), 
            json => json.FromLegacyJson<User>());

        // Test 2: DataContractJsonSerializer
        RunBenchmark("DataContractJsonSerializer", sourceData, 
            data => data.ToDataContractJson(), 
            json => json.FromDataContractJson<User>());

        // Test 3: Newtonsoft.Json
        RunBenchmark("Newtonsoft.Json", sourceData, 
            data => JsonConvert.SerializeObject(data), 
            json => JsonConvert.DeserializeObject<User>(json));

        Console.ReadLine();
    }

    public static void RunBenchmark<T>(string libraryName, List<T> originalData, 
        Func<T, string> serializeFunc, Func<string, T> deserializeFunc)
    {
        var serializedStrings = new List<string>();
        var deserializedData = new List<T>();
        
        // Serialization Phase
        var watch = Stopwatch.StartNew();
        foreach (var item in originalData)
        {
            serializedStrings.Add(serializeFunc(item));
        }
        watch.Stop();
        Console.WriteLine($"[{libraryName}] Serialization of {originalData.Count} items took: {watch.ElapsedMilliseconds} ms");

        // Deserialization Phase
        watch.Restart();
        foreach (var jsonStr in serializedStrings)
        {
            deserializedData.Add(deserializeFunc(jsonStr));
        }
        watch.Stop();
        Console.WriteLine($"[{libraryName}] Deserialization of {serializedStrings.Count} items took: {watch.ElapsedMilliseconds} ms\n");
    }
}

5. Performance Analysis Results

Testing was conducted with varying data volumes to observe scalability. The findings are summarized below:

Strongly Typed Objects

  • Small Datasets (100 - 1,000 items): Performance differences between the three libraries are negligible. Execution times are nearly identical.
  • Large Datasets (>10,000 items): Significant discrepancies emerge. JavaScriptSerializer shows a marked decrease in efficiency as data volume increases. Both DataContractJsonSerializer and Newtonsoft.Json maintain superior performance, with Newtonsoft.Json often showing a slight edge in speed.

Weakly Typed DataTable

  • JavaScriptSerializer: This method frequently encounters errors or requires complex handling when attempting to serialize DataTable structures directly.
  • DataContractJsonSerializer: While capable, this serializer often converts DataTable structures into an XML-like JSON format or requires explicit configuration for table names, making it less intuitive for standard JSON data exchange.
  • Newtonsoft.Json: This library handles DataTable serialization seamlessly, producing standard JSON that is easy to consume and parse.

Conclusion

For most modern .NET applications, Newtonsoft.Json offers the best balance of performance and ease of use, particularly when dealing with complex structures like DataTable or large volumes of data. While DataContractJsonSerializer is a viable native alternative, JavaScriptSerializer should generally be avoided for performance-critical or large-scale operations due to its degradation in speed as dataset size increases.

Tags: C# JSON serialization Newtonsoft.Json Performance

Posted on Wed, 01 Jul 2026 16:33:01 +0000 by shatteredroses