Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 773
Pavel Voronin Avatar asked Jun 25 '20 07:06

Pavel Voronin


People also ask

How do I ignore JSON property based on condition?

To ignore individual properties, use the [JsonIgnore] attribute. You can specify conditional exclusion by setting the [JsonIgnore] attribute's Condition property.

Which is better Newtonsoft JSON or System text JSON?

Json does case-insensitive property name matching by default. The System. Text. Json default is case-sensitive, which gives better performance since it's doing an exact match.

Is Newtonsoft JSON obsolete?

Yet Newtonsoft. Json was basically scrapped by Microsoft with the coming of . NET Core 3.0 in favor of its newer offering designed for better performance, System.

What is Jsonconvert DeserializeObject?

DeserializeObject<T>(String,JsonConverter[]) Deserializes the JSON to the specified . NET type using a collection of JsonConverter. DeserializeObject(String, JsonSerializerSettings) Deserializes the JSON to a .


Video Answer


3 Answers

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

like image 120
vivek nuna Avatar answered Oct 17 '22 05:10

vivek nuna


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
}
like image 3
Panagiotis Kanavos Avatar answered Oct 17 '22 05:10

Panagiotis Kanavos


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);
like image 1
ShadyNagy Avatar answered Oct 17 '22 06:10

ShadyNagy