.NET
JSON
serialization
lowercase keys
coding best practices

Ensuring json keys are lowercase in .NET

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

If an API contract requires JSON property names such as userid instead of userId or UserId, the built-in defaults in .NET are not enough by themselves. System.Text.Json includes camel case support out of the box, but fully lowercase keys require a custom naming policy.

Lowercase Object Property Names with System.Text.Json

The core mechanism is JsonNamingPolicy. You create a custom policy that converts every property name to lowercase and then assign it through JsonSerializerOptions.PropertyNamingPolicy.

csharp
1using System;
2using System.Text.Json;
3
4public sealed class LowerCaseNamingPolicy : JsonNamingPolicy
5{
6    public override string ConvertName(string name) =>
7        name.ToLowerInvariant();
8}
9
10public sealed class UserDto
11{
12    public int UserId { get; set; }
13    public string DisplayName { get; set; } = "";
14}
15
16public static class Program
17{
18    public static void Main()
19    {
20        var options = new JsonSerializerOptions
21        {
22            PropertyNamingPolicy = new LowerCaseNamingPolicy(),
23            WriteIndented = true
24        };
25
26        var user = new UserDto { UserId = 7, DisplayName = "Ava" };
27        string json = JsonSerializer.Serialize(user, options);
28
29        Console.WriteLine(json);
30    }
31}

The output is:

json
1{
2  "userid": 7,
3  "displayname": "Ava"
4}

That is different from the built-in camel case policy, which would have produced userId and displayName.

Lowercase Dictionary Keys Too

If your payload also contains Dictionary<string, TValue> values, set DictionaryKeyPolicy as well.

csharp
1var options = new JsonSerializerOptions
2{
3    PropertyNamingPolicy = new LowerCaseNamingPolicy(),
4    DictionaryKeyPolicy = new LowerCaseNamingPolicy(),
5    WriteIndented = true
6};

This matters because object properties and dictionary keys are handled separately. Configuring one does not automatically configure the other.

ASP.NET Core Global Configuration

In an ASP.NET Core API, you can apply the policy globally:

csharp
1using Microsoft.AspNetCore.Builder;
2using Microsoft.Extensions.DependencyInjection;
3
4var builder = WebApplication.CreateBuilder(args);
5
6builder.Services
7    .AddControllers()
8    .AddJsonOptions(options =>
9    {
10        var lower = new LowerCaseNamingPolicy();
11        options.JsonSerializerOptions.PropertyNamingPolicy = lower;
12        options.JsonSerializerOptions.DictionaryKeyPolicy = lower;
13    });
14
15var app = builder.Build();
16app.MapControllers();
17app.Run();

After that, controller responses use the lowercase naming policy automatically.

Attribute Overrides Still Win

System.Text.Json also supports [JsonPropertyName]. If you apply that attribute, it overrides the naming policy for that property.

csharp
1using System.Text.Json.Serialization;
2
3public sealed class WeatherDto
4{
5    [JsonPropertyName("temp_c")]
6    public int TemperatureCelsius { get; set; }
7
8    public string Summary { get; set; } = "";
9}

That gives you an escape hatch when one field must follow a special external contract.

What About Newtonsoft.Json?

If your project still uses Newtonsoft.Json, the idea is similar, but the configuration point is different. You would typically use a custom NamingStrategy inside a contract resolver. The principle is the same: define the transformation once and apply it centrally rather than renaming properties all over the codebase.

For new ASP.NET Core projects, System.Text.Json is usually the default and should be the first option unless you need a feature that only Newtonsoft provides.

Be Careful with Deserialization Expectations

Property naming policy applies to serialization and deserialization of object property names, but dictionary-key naming policy only affects serialization. That means dictionary keys are not automatically normalized to lowercase when reading JSON back in.

If the inbound contract is also strict, test both directions explicitly rather than assuming symmetry.

Common Pitfalls

The first pitfall is assuming JsonNamingPolicy.CamelCase is lowercase. It is not. It only lowers the initial character according to camel-case rules.

Another pitfall is forgetting dictionary keys. You may serialize object properties in lowercase while nested dictionary keys still come out with their original casing.

A third pitfall is using [JsonPropertyName] in a few places and then wondering why those members ignore the global policy. The attribute has higher precedence.

Finally, consider API compatibility. Changing key casing is a contract change and can break existing clients, so do it deliberately.

Summary

  • Fully lowercase JSON keys in .NET require a custom JsonNamingPolicy
  • Set PropertyNamingPolicy for object properties and DictionaryKeyPolicy for dictionary keys
  • In ASP.NET Core, configure the policy once through AddJsonOptions
  • '[JsonPropertyName] overrides the global naming policy'
  • Do not confuse camel case with fully lowercase output

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.