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