1

Using System.Text.Json for Camel Case Serialization

 1 year ago
source link: https://code-maze.com/csharp-using-system-text-json-for-camel-case-serialization/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Using System.Text.Json for Camel Case Serialization

Posted by Code Maze | May 25, 2023 | 0

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

In this article, we’ll learn how to use System.Text.Json for camel case serialization in .NET 7.

First, we’ll take a glance at the default behavior when serializing. Then we’ll use two different ways for the camel case serialization. Lastly, we’ll discuss how we can make our code cleaner.

To download the source code for this article, you can visit our GitHub repository.

Let’s take a look.

Default Serialization Behavior

By default, JsonSerializer will use the same property names when serializing or deserializing with System.Text.Json.

Let’s define a Person class:

public class Person
public string? FirstName { get; set; }
public string? Surname { get; set; }
public int? Age { get; set; }
public bool? IsActive { get; set; }
public class Person
{
    public string? FirstName { get; set; }
    public string? Surname { get; set; }
    public int? Age { get; set; }
    public bool? IsActive { get; set; }
}

The reason why we are using the nullable type for Age and IsActive is when we deserialize JSON string to a Person object, if  Age or IsActive are not provided, they will be deserialized to the default value (zero and false). But if we define them with the nullable type, they will be deserialized to null, which is what we want here.

If we try to serialize an instance of Person:

var person = new Person()
Age = 20,
FirstName = "John",
Surname = "Doe",
IsActive = true
Console.WriteLine($"{JsonSerializer.Serialize(person)}");
var person = new Person()
{
    Age = 20,
    FirstName = "John",
    Surname = "Doe",
    IsActive = true
};
Console.WriteLine($"{JsonSerializer.Serialize(person)}");

When we run the application, we will get the result:

{"FirstName":"John","Surname":"Doe","Age":20,"IsActive":true}
{"FirstName":"John","Surname":"Doe","Age":20,"IsActive":true}

By default, the object can only be serialized or deserialized with the same property names in the JSON string.

But, what if we want to use JSON keys in the camel case in serialization? We have several ways to achieve that.

Use JsonPropertyName Attribute for Camel Case Serialization

One way to implement this is to add an [JsonPropertyName] attribute on properties with specific names. With this approach, we can define another class:

public class PersonWithAttributes
[JsonPropertyName("firstName")]
public string? FirstName { get; set; }
[JsonPropertyName("surname")]
public string? Surname { get; set; }
[JsonPropertyName("age")]
public int? Age { get; set; }
[JsonPropertyName("isActive")]
public bool? IsActive { get; set; }
public class PersonWithAttributes
{
    [JsonPropertyName("firstName")]
    public string? FirstName { get; set; }
    
    [JsonPropertyName("surname")]
    public string? Surname { get; set; }
    
    [JsonPropertyName("age")]
    public int? Age { get; set; }
    
    [JsonPropertyName("isActive")]
    public bool? IsActive { get; set; }
}

Next, we can serialize it:

var personWithAttributes = new PersonWithAttributes
Age = 20,
FirstName = "John",
Surname = "Doe",
IsActive = true
Console.WriteLine($"{JsonSerializer.Serialize(personWithAttributes)}");
var personWithAttributes = new PersonWithAttributes
{
    Age = 20,
    FirstName = "John",
    Surname = "Doe",
    IsActive = true
};
Console.WriteLine($"{JsonSerializer.Serialize(personWithAttributes)}");

And, we can inspect the result:

{"firstName":"John","surname":"Doe","age":20,"isActive":true}
{"firstName":"John","surname":"Doe","age":20,"isActive":true}
Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

Notice the different naming convention from the default one.

If we have a JSON string in camel case, after we deserialize it, we can parse it correctly:

var personString = """{"firstName":"John","surname":"Doe","age":20,"isActive":true}""";
var personFromString = JsonSerializer.Deserialize<PersonWithAttributes>(personString);
Console.WriteLine($"{personFromString.FirstName} {personFromString.Surname}({personFromString.IsActive}) is {personFromString.Age}");
var personString = """{"firstName":"John","surname":"Doe","age":20,"isActive":true}""";
var personFromString = JsonSerializer.Deserialize<PersonWithAttributes>(personString);
Console.WriteLine($"{personFromString.FirstName} {personFromString.Surname}({personFromString.IsActive}) is {personFromString.Age}");

Each property will be assigned with correct value:

John Doe(True) is 20
John Doe(True) is 20

This is quite a simple approach in some situations and it has its pros:

  • Easy to implement
  • We can specify any name we want to use when serializing

But also, this approach comes with obvious cons: we need to set every property’s name one by one manually.

Now let’s take a look at another approach.

Use JsonSerializerOptions Parameter for Camel Case Serialization

Both JsonSerializer.Serialize and JsonSerializer.Deserialize<T> methods have overloads that receive a second parameter of type JsonSerializerOptions, so we can pass it in with a proper configuration.

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

Let’s take a look at how to use it:

var person = new Person()
Age = 20,
FirstName = "John",
Surname = "Doe",
IsActive = true
JsonSerializer.Serialize(person, new JsonSerializerOptions
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
var person = new Person()
{
    Age = 20,
    FirstName = "John",
    Surname = "Doe",
    IsActive = true
};
JsonSerializer.Serialize(person, new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});

By adding a JsonSerializerOptions parameter, we provide a specific naming convention. The result will be the same as the first approach.

Pros of this approach can be:

  • Easy to implement as well
  • Camel case is a built-in naming convention
  • It comes with much more configuration controls when serializing
  • We don’t have to modify entity properties manually

When we choose this approach, some restrictions may raise our concerns:

  • It is hard and tricky to configure naming policy project-wide
  • We have to add the parameter of type JsonSerializerOptions in every method call, which is easy to forget
  • What if we want some naming conventions other than built-in ones

There are ways to solve these issues. In the next section, we will talk about how to resolve the first and the second issue; as for the third, we can define our naming policy, but it’s unrelated to this article so we will ignore that for now.

Make Our Code Cleaner

In the second approach, we must always add the parameter of type JsonSerializerOptions when we want to serialize or deserialize. That is easy to forget and quite annoying to do for every call.

System.Text.Json does not provide a convenient way to configure the naming policy for the whole project. Instead of going with not so easy way to do it, the easier way is to use an extension methods:

public static class JsonSerializerExtensions
public static string SerializeWithCamelCase<T>(this T data)
return JsonSerializer.Serialize(data, new JsonSerializerOptions
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
public static T DeserializeFromCamelCase<T>(this string json)
return JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
public static class JsonSerializerExtensions
{
    public static string SerializeWithCamelCase<T>(this T data)
    {
        return JsonSerializer.Serialize(data, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
    }

    public static T DeserializeFromCamelCase<T>(this string json)
    {
        return JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
    }
}

Then we can use our extension method to do serialization:

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<
person.SerializeWithCamelCase();
person.SerializeWithCamelCase();

Or deserialization:

personString.DeserializeFromCamelCase<Person>()
personString.DeserializeFromCamelCase<Person>()

Both methods will give us the correct result, making our code easier to write.

Conclusion

By looking into these two approaches for camel case serialization using System.Text.Json, both methods have pros and cons. Understanding requirements is the first step to choosing which to use or using different techniques for different scenarios.

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

Share:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK