Search code examples
c#jsonasp.net-coreasp.net-core-webapicamelcasing

ASP.NET Core 3.1 web API JSON response camelizes more than first character


In our web API we have legacy entities that have abbreviated names. We are also using code generation via T4 templates, where we like to keep things simple and predictable:

  • Template creates C# classes and capitalize the first character of the properties
  • Template creates Angular code and lowercase the first character of the properties

The JSON response from the web API however does some magic on deciding which letters to convert to lowercase, instead of only the expected first character.

For example, when starting a new default web API in Visual Studio and adding two properties to the WeatherForecast.cs:

public string TSTValue { get; set; }
public string TSTVL1 { get; set; }

The result is:

[
  {
    ...
    "tstValue":null,
    "tstvL1":null
  },
  {
    ...
    "tstValue":null,
    "tstvL1":null
  }
]

The expected/desired output would be a result with the camelcase property names:

[
  {
    ...
    "tSTValue":null,
    "tSTVL1":null
  },
  {
    ...
    "tSTValue":null,
    "tSTVL1":null
  }
]

How can the magic behavior be overridden?


Solution

  • Firstly the behavior you describe is intended. You can view the source code on Github https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonCamelCaseNamingPolicy.cs Thankfully the name serialization can be customized with relative ease.

    Since you specified that you don't want to use attributes you can create your own JsonNamingPolicy which can be used to serialize the field names in anyway you see fit.

    Below I have created a basic class which ensures that the first character is lower case and leaves the rest of the field string alone. ConvertName(string name) will be called for each field in the serialized class. In your example that is TSTValue and TSTVL1

    public class JsonFirstCharToLowerNamingPolicy : JsonNamingPolicy
    {
        public override string ConvertName(string name)
        {
            // if the string is empty or the first character is already lowercase just return as is
            if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
                return name;
    
            char[] chars = name.ToCharArray(); // get a list of chars
            chars[0] = char.ToLowerInvariant(chars[0]); // make the first character lower case 
    
            // leave the rest of the characters alone or do more processing on it?
    
            return new string(chars); // return the altered string
        }
    }
    

    To use the class you would simply just have to set the JsonSerializerOptions of the JsonSerializerOptions as shown below.

    var serializeOptions = new JsonSerializerOptions
    {
        PropertyNamingPolicy = new JsonFirstCharToLowerNamingPolicy(),
        WriteIndented = true
    };
    var jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);