Hello there

My current technology stack: .NET 9, Python, TypeScript, and Azure.

I develop microservices and terraform of different sizes. Sharing my challenges and key learning.

About

The views expressed in this blog are my own and do not reflect my employer's. I am not responsible for any consequences of using the information provided. This blog is for educational purposes only, not for commercial use. Readers should apply their own judgment.

Optimizing High-Performance APIs JSON Serialization in .NET 9

March 09, 2025 Dipankar Haldar 35 people viewed this post

Optimizing JSON Serialization in .NET 9 for High-Performance APIs

Introduction

Serialization is a critical aspect of modern web applications, especially for APIs that need to process large amounts of data efficiently. With the improvements in .NET 9, JSON serialization performance has been enhanced further.

In this article, we benchmark different serialization approaches and explore optimizations that can significantly improve API response performance.


The Real-Life Problem: Large API Responses

Consider an e-commerce API that returns large lists of products, including details like names, descriptions, prices, and stock levels.

⚠️ Inefficient JSON serialization can:
✔️ Slow down API response times
✔️ Lead to poor user experience
✔️ Increase infrastructure costs


Benchmarking JSON Serialization in .NET 9

We benchmark the following approaches:

1️⃣ System.Text.Json (Default in .NET 9)
2️⃣ Newtonsoft.Json (Json.NET, widely used in legacy applications)
3️⃣ Optimized System.Text.Json with Custom Settings
4️⃣ System.Text.Json with Source Generation


Benchmark Setup

The test data consists of 10,000 product records.

[MemoryDiagnoser]
public class JsonSerializationBenchmark
{
    private readonly List<Product> _products;
    private readonly JsonSerializerOptions _optimizedOptions;

    public JsonSerializationBenchmark()
    {
        _products = GenerateProducts(10000);
        _optimizedOptions = new JsonSerializerOptions { WriteIndented = false, DefaultBufferSize = 16384 };
    }

    [Benchmark]
    public string SystemTextJson_Default() => JsonSerializer.Serialize(_products);
    
    [Benchmark]
    public string NewtonsoftJson() => JsonConvert.SerializeObject(_products);
    
    [Benchmark]
    public string SystemTextJson_Optimized() => JsonSerializer.Serialize(_products, _optimizedOptions);
    
    [Benchmark]
    public string SystemTextJson_SourceGen() => JsonSerializer.Serialize(_products, MyJsonContext.Default.ListProduct);

    private List<Product> GenerateProducts(int count)
    {
        var list = new List<Product>();
        for (int i = 0; i < count; i++)
        {
            list.Add(new Product { Id = i, Name = $"Product {i}", Price = i * 1.1m });
        }
        return list;
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

[JsonSourceGenerationOptions(WriteIndented = false)]
[JsonSerializable(typeof(List<Product>))]
internal partial class MyJsonContext : JsonSerializerContext {}

Benchmark Results

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4974/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-1370P, 1 CPU, 20 logical and 14 physical cores
.NET SDK 9.0.103
  [Host]     : .NET 9.0.2 (9.0.225.6610), X64 RyuJIT AVX2 [AttachedDebugger]
  DefaultJob : .NET 9.0.2 (9.0.225.6610), X64 RyuJIT AVX2
Performance Comparison
🛠 Method 🚀 Mean 🎯 Error 🔄 StdDev 📍 Median 📉 Gen0 📉 Gen1 📉 Gen2 📦 Allocated
SystemTextJson_Default 1,881.2 us 104.46 us 304.72 us 1,998.6 us 199.2188 199.2188 199.2188 953.51 KB
NewtonsoftJson 3,228.1 us 207.29 us 611.19 us 3,667.6 us 246.0938 246.0938 246.0938 2842.01 KB
SystemTextJson_Optimized 1,246.1 us 12.49 us 11.68 us 1,248.1 us 199.2188 199.2188 199.2188 953.75 KB
SystemTextJson_SourceGen 816.6 us 4.63 us 3.61 us 817.5 us 199.2188 199.2188 199.2188 952.72 KB

Key Takeaways

System.Text.Json is significantly faster than Newtonsoft.Json.
Optimizing System.Text.Json further reduces serialization time and memory usage.
Source Generation offers the best performance, with lower serialization time and memory allocation.
Memory allocation is significantly lower when using System.Text.Json settings effectively.


Conclusion

If building high-performance APIs in .NET 9, replacing Newtonsoft.Json with System.Text.Json and leveraging source generation can lead to significant performance improvements.

🚀 Optimizing serialization reduces response time, enhances scalability, and improves overall API performance.