How to force System.Text.Json serializer throw exception when property is missing?
Asked Answered
D

5

16

Json.NET behaviour could be defined by attributes: either use default or just throw an exception if json payload does not contain required property.

Yet System.Text.Json serializer silently does nothing.
Having class:

public sealed class Foo
{
    [Required]
    public int Prop {get;set;} = 10;
}

and deserializing empty object:

JsonSerializer.Deserialize<Foo>("{}");

I simply get an instance of Foo with Prop=10. I could not find any setting in JsonSerializerOptions to force it throw an exception. Is it possible?

Danu answered 25/6, 2020 at 7:34 Comment(3)
According to required properties you should create custom converterMythical
System.Text.Json isn't a full replacement for Json.NET. It's built for speed with minimal allocations in mind, not feature completeness. If you want validations you can 1) use Json.NET 2) validate the objects after serialisation with the Validator class or 3) create a custom converterGame
Check Manual Validation with Data Annotations for the 2nd optionGame
K
5

System.Text.Json doesn't throw an exception if no value is received for one of the properties of the target type. You need to implement a custom converter.

Reference: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#required-properties

Kenon answered 25/6, 2020 at 7:48 Comment(0)
G
5

System.Text.Json isn't a full replacement for Json.NET. It's built for speed with minimal allocations in mind, not feature completeness. If you want validations you can

  1. Use Json.NET
  2. Validate the objects after serialisation with the Validator class
  3. Create a custom converter

TheGeneral showed how to do #3. A custom validator would have to handle all validations explicitly and return some meaningful exception though. Throwing an ArgumentNullException is enough if there's only a single property to check. Validating multiple properties would require something more complex like a ValidationException to include the validation results.

K. Scott Allen's article Manual Validation with Data Annotations shows how to do #2.

One option is to use the Validator.ValidateObject to validate an object and get a ValidationException with all the failing validations :

try
{
    var validationCtx=new ValidationContexgt(myFoo);
    Validator.ValidateObject(myFoo,validationCtx);
}
catch(ValidatinException ex)
{
    //Do something with the results.
}

This is OK if invalid objects are rare, as throwing exceptions is expensive. Perhaps a better option is to use Validator.TryValidateObject :

var results = new List<ValidationResult>();
var validationCtx=new ValidationContexgt(myFoo);
if(Validator.TryValidateObject(myFoo,validationCtx,results))
{
    //Use the object
}
else
{
    //Do something with the failed results
}
Game answered 25/6, 2020 at 8:15 Comment(1)
The problem with validation is that default instance may be absolutely valid, but at the time of validating we won't knkow whether payload was correct.Danu
M
5

The [JsonRequired] attribute from System.Text.Json works as requested, but it is available starting with .NET 7. See Required properties documentation.

In addition, in .NET 8 you can also force the JSON string to properly map to POCO/model properties using JsonUnmappedMemberHandling.Disallow option. See Handle missing members during deserialization documentation.

Margenemargent answered 27/4, 2023 at 19:11 Comment(1)
Hm, it would be much better if missing property handling was a setting in JsonSerializerOptions as well, because on may need to allow/disallow missing properties based on the use case rather than on the model.Looselimbed
A
1

All you need to do SetMissingMemberHandling and it will handle every thing for you but you need to install DevBetter.JsonExtensions MissingMemberHandling.Ignore and MissingMemberHandling.Error

var deserializeOptions = new JsonSerializerOptions()
    .SetMissingMemberHandling(MissingMemberHandling.Ignore);

var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, deserializeOptions);
Architect answered 28/10, 2021 at 21:7 Comment(0)
T
0

Pass in an implementation of DefaultJsonTypeInfoResolver, which marks every property as required.

using System.Text.Json;

var options = new JsonSerializerOptions {
    TypeInfoResolver = new DefaultJsonTypeInfoResolver {
        Modifiers = {
            typeInfo => {
                foreach (JsonPropertyInfo property in typeInfo.Properties) {
                    property.IsRequired = true;
                }
            }
        }
    }
};

return JsonSerializer.Deserialize<T>(content, options);
Tutti answered 18/7, 2023 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.