Probably there’s no need for me to say why .NET Core 3.0 is a big deal. There are enough articles on that. For a great write-up see Announcing .NET Core 3.0.

From the inception of the .NET Core project, we’ve added around fifty thousand .NET Framework APIs to the platform. .NET Core 3.0 closes much of the remaining capability gap with .NET Framework 4.8.

Introducing .NET 5

Next to adding this massive amount of .NET Framework APIs, they’ve also added some new ones. And while they won’t be adding any extra .NET Framework APIs anymore, new APIs will keep pouring in.

One of the very interesting ones already available right now: System.Text.Json. To get a head start on how to use it, see Try the new System.Text.Json APIs.

JsonNamingPolicy

The JsonNamingPolicy determines the naming policy used to convert property name to another format. Like the well-known camelCasing format. But sometimes, systems/requirements ask for a different naming policy. Today I encountered a naming policy where a property name SomeProperty would result in a Json property name some_property. There’s no naming policy for that one…

The nice thing about the new Json APIs: we can create one ourselves!

The System.Text.Json serializer can read and write JSON asynchronously and is optimized for UTF-8 text […]

By default, we produce minified JSON.

Immo Landwerth @ Try the new System.Text.Json APIs

Let’s code! 🤓

First we’re creating a custom JsonNamingPolicy to implement converting the name:

public class CustomJsonNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }
        var result = new StringBuilder();
        for (var i = 0; i < name.Length; i++)
        {
            var c = name[i];
            if (i == 0)
            {
                result.Append(char.ToLower(c));
            }
            else
            {
                if (char.IsUpper(c))
                {
                    result.Append('_');
                    result.Append(char.ToLower(c));
                }
                else
                {
                    result.Append(c);
                }
            }
        }
        return result.ToString();
    }
}

Next up: using the newly created naming policy:

var options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = new CustomJsonNamingPolicy()
    };
var result = JsonSerializer.Deserialize<MyClass>(json, options);

With Json.NET we had DefaultSettings which enabled us to set settings like the contract resolver only once. With System.Text.Json this isn’t possible (yet?). There’s an open GitHub issue “Change JsonSerializer default settings” that goes into this.

Current solutions/workarounds range from simply specifying the options for each call, to implementing a wrapper around JsonSerializer so you can specify the options once and then only use the wrapper.

Of course, there are possible error scenarios with solutions, so I’ll be keeping an eye on the GitHub issue above. For now I’ve chosen the solution where I have a static instance of the desired options and I used them for each call.

public sealed class DefaultJsonSerializerOptions
{
    public static readonly JsonSerializerOptions Options = new JsonSerializerOptions
    {
        IgnoreNullValues = true,
        PropertyNamingPolicy = new CustomJsonNamingPolicy()
    };
}
var result = JsonSerializer.Deserialize<MyClass>(json, DefaultJsonSerializerOptions.Options);

Conclusion

It’s awesome that Json serialization is now available in .NET Core 3 by default. Stuff like being able to roll your own naming policy being available from the start is great. I’ll be keeping a close eye on the future developments to see where it’s heading.

If you have any questions or would like to discuss, don’t hesitate to contact me.

The featured image is a photo by fabio on Unsplash.