Pavel Voronin
Pavel Voronin

Reputation: 13983

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

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?

Upvotes: 17

Views: 12302

Answers (6)

Pierre Arnaud
Pierre Arnaud

Reputation: 10527

In System.Text.Json you can set RespectRequiredConstructorParameters property on the JsonSerializerOptions to true. With that, trying to deserialize "{}" for:

record Foo(string Text);

will throw a JsonException:

JSON deserialization for type 'Foo' was missing required properties including: 'Text'.

See https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.respectrequiredconstructorparameters

Upvotes: 0

Danon
Danon

Reputation: 2973

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);

Upvotes: 0

MatrixRonny
MatrixRonny

Reputation: 781

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.

Upvotes: 5

ShadyNagy
ShadyNagy

Reputation: 19

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);

Upvotes: 1

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131364

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
}

Upvotes: 5

Vivek Nuna
Vivek Nuna

Reputation: 1

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

Upvotes: 5

Related Questions