Recently, I've been working with an API that for example's sake returned a JSON response something like this:
"
{
"name":"Foo",
"last_name":"bar"
}
"
The task's requirement was to use .Net Core's System.Text.Json to deserialiaze the JSON into an object of a Person class. So I start off by writing the person class like below:
public class Person
{
public string Name { get; set; }
[JsonPropertyName("last_name")]
public string LastName { get; set; }
}
Then I would write the deserialization code:
var deserializationOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
var person = JsonSerializer.Deserialize<Person>(apiJsonResponse, deserializationOptions);
Notice that in order for me to correctly deserialiaze the JSON properties, I had to do two things:
1. Configure the JsonSerializerOptions to ignore the case
This is because the API response returns the JSON property names in lower case but my C# class properties are in Pascal case as per C# standard naming conventions. By default, System.Text.Json is case sensitive. So in order for it to ignore property name cases, we had to pass in the JSON serializer options.
2. Add a JsonPropertyName attribute for the LastName C# class property
This is due to the API's JSON response using "last_name" as the property name. However, my C# class property uses LastName.
So all seems good so far.
The second part of my task is to do some processing on the Person object by converting the Person's Name from 'Foo' to 'Baz'. This is followed by returning the processed Person object from a function as a serialized JSON string.
And now this this is where the problem arises.
When I directly serialize the processed Person object after the doing the initial deserialization, we will get the following JSON string:
"
{
"Name": "Baz",
"last_name": "bar"
}
"
Ideally, for the task, I needed to return the JSON as below instead:
"
{
"Name": "Baz",
"LastName": "bar"
}
"
This issue happens because the JsonPropertyName attribute is used for both Serialization and Deserialization.
As workarounds, the only options I know so far of are:
1. Create a separate object to deserialize to. Maybe implement some form of interface to reduce unnecessary code duplicates
2. Create a custom converter
Seeing as how as it is a non-significant program and that there are time constraints (but of course), creating a custom converter was a no-go. Option 1 would be the easiest but I did not want to manage too many classes and code files for such a small project.
So the laziest and fastest approach, I could think of was to simply create an auxiliary property just for deserialization purpose.
Using this lazy approach, now my Person class looks like below:
public class Person
{
public string Name { get; set; }
[JsonPropertyName("last_name")]
public string InternalLastName
{
set { LastName = value; }
}
public string LastName { get; set; }
}
Obviously this method has some drawbacks.
The first being that you now have an additional property whose only function is for JSON deserialization purposes which will be very confusing for the next coder who will work on this code . And It will also be confusing for whoever is going to consume this class as a library.
As an improvement for the latter, we can always set the access modifier of the auxiliary property as internal or private but unfortunately System.Text.Json only supports public properties.
However, last I checked, this would be changed in .Net 5 https://github.com/dotnet/runtime/pull/34675.