How to Configure JSON Serializer options in ASP.NET Core

By FoxLearn 2/4/2025 8:14:34 AM   8
ASP.NET Core uses System.Text.Json as the default JSON serializer. To customize the JSON serializer options globally, you can use the AddJsonOptions() method in the initialization code.
using System.Text.Json.Serialization;

builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

The AddJsonOptions() method provides access to the global JsonSerializerOptions object, which is used across all requests and responses. You can configure these options and add custom converters, including your own.

By default, ASP.NET Core uses JsonSerializerDefaults.Web with JsonSerializerOptions, which applies the following settings:

PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
NumberHandling = JsonNumberHandling.AllowReadingFromString

These options can be customized in AddJsonOptions().

Configure JSON Options for a Single Response

While AddJsonOptions() configures global JSON options, you may want to configure the JSON options for a single response. You can achieve this using JsonResult with a custom JsonSerializerOptions.

using System.Text.Json;
using System.Text.Json.Serialization;
using System.Net;

[HttpGet("product/{id}")]
public async Task<IActionResult> GetProduct(int id)
{
    var product = await GetProductByIdAsync(id);

    var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
    options.Converters.Add(new JsonStringEnumConverter());

    return new JsonResult(product, options)
    {
        StatusCode = (int)HttpStatusCode.OK
    };
}

For the above endpoint, the output will be something like this:

{
    "id": 101,
    "name": "Laptop",
    "price": 1499.99,
    "availabilityStatus": "InStock"
}

In this case, JsonSerializerDefaults.Web is used to configure the default options. Additionally, a JsonStringEnumConverter is added to handle enums as strings in the serialized JSON.

This approach is simple and works well for most cases. However, there's a slight performance tradeoff when creating new JsonSerializerOptions for each response. Reusing the JsonSerializerOptions across multiple requests would be more efficient, especially in high-traffic applications, though the performance impact is typically minimal.

If you'd like to use Newtonsoft JSON for more customization, you can easily switch over by using AddNewtonsoftJson().

using Newtonsoft.Json.Serialization;

builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
    // Customize the naming strategy to kebab-case
    options.SerializerSettings.ContractResolver = new DefaultContractResolver()
    {
        NamingStrategy = new KebabCaseNamingStrategy()
    };
});

Make sure to install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package if you decide to use Newtonsoft JSON.

After configuring it, sending a request like:

GET https://localhost:12345/products

Will return the following JSON with properties in kebab-case:

{
    "product-id": 101,
    "product-name": "Laptop",
    "product-price": 1499.99,
    "availability-status": "InStock"
}

This illustrates the flexibility in customizing JSON serialization and adopting different strategies based on your application's needs.