I had a requirement where I want to enforce some property values to be present before deserializing the JSON string. And with .NET 7, you can do that pretty easily (another reason to move to .NET 7).
In this post, let's see how we can enforce the required properties for deserialization. There are three ways,
- By adding the required modifier (required modifier is introduced with C# 11).
- By annotating it with JsonRequiredAttribute (JsonRequiredAttribute attribute is introduced with .NET 7).
- By modifying the JsonPropertyInfo.IsRequired property of the contract model (this again is introduced with .NET 7).
Failing to provide a required property will throw a JsonException.
Let's have a look.
By adding the required modifier
Consider the following POCO class. Here I have applied required modifier to FirstName and LastName.
public record Person
{
public required string FirstName { get; set; }
public string? MiddleName { get; set; }
public required string LastName { get; set; }
}
And let's try to deserialize the following string.
string @string = """
{
"FirstName": "John",
"LastName": "Doe"
}
""";
try
{
Person? person = JsonSerializer.Deserialize<Person>(@string);
}
catch (JsonException jsonException)
{
Console.WriteLine(jsonException.Message);
}
The above code is successfully deserializing the string into a person. Because the string has required properties set.
Now let's try the below. I am removing the LastName from JSON string.
string @string = """
{
"FirstName": "John"
}
""";
try
{
Person? person = JsonSerializer.Deserialize<Person>(@string);
}
catch (JsonException jsonException)
{
Console.WriteLine(jsonException.Message);
// JSON deserialization for type 'Person' was missing required properties, including the following: LastName
}
This will fail because our string doesn't contain the LastName property.
By annotating it with JsonRequiredAttribute
We can achieve the same result as above by using JsonRequiredAttribute. So instead of adding required modifier, we can decorate the property with JsonRequiredAttribute.
public record Person
{
[JsonRequired]
public string FirstName { get; set; }
public string? MiddleName { get; set; }
[JsonRequired]
public string LastName { get; set; }
}
By modifying the JsonPropertyInfo.IsRequired property of the contract model
This is kind of a more advanced approach.
string @string = """
{
"FirstName": "John"
}
""";
var jsonSerializerOptions = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers =
{
static typeInfo =>
{
if (typeInfo.Kind != JsonTypeInfoKind.Object)
{
return;
}
foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
propertyInfo.IsRequired = propertyInfo.Name switch
{
nameof(Person.FirstName) or nameof(Person.LastName) => true,
_ => false
};
}
}
}
}
};
try
{
// This time we are passing the jsonSerializerOptions Person? person = JsonSerializer.Deserialize<Person>(@string, jsonSerializerOptions);
}
catch (JsonException jsonException)
{
Console.WriteLine(jsonException.Message);
// JSON deserialization for type 'Person' was missing required properties, including the following: LastName
}
The above will also throw a JsonException with a message saying Required properties aren't set.
Hope this helps.
Happy Coding.
Regards,
Jaliya
No comments:
Post a Comment