0

If I have a DTO class containing value type properties, how can I idiomatically use Newtonsoft to deserialize JSON to my DTO class while ensuring that the JSON defines the value type, possibly containing the default value for the type? So far the methods I have seen rely on checking if the value is the default value, however, this is not a suitable solution when the default value is also a valid value for the property.

Example

public class MyDto
{
    public bool MyProp { get; set; }
}
JSON Can deserialize to MyDto
{"MyProp": true} true
{"MyProp": false} true
{} false

Current solution

Currently I use System.ComponentModel.DataAnnotations.RequiredAttribute and declare the type as nullable, but this only works during model binding (instead of any deserialization), and leads to excessive use of ! when referencing the property.

public class MyDto
{
    [Required]
    public bool? MyProp { get; set; }
}
twinlakes
  • 9,438
  • 6
  • 31
  • 42
  • 1
    What do you want to happen, when JSON is `{}` ? – Poul Bak Apr 10 '21 at 01:53
  • The deserializer should not succeed. If it's an `ApiController` model, the client should receive a 400, if it's a `JsonConvert` call, it should throw. – twinlakes Apr 10 '21 at 02:36
  • We need to see your ApiController and even a fully reproducible example. Otherwise it is very difficult to figure out what the problem actually is. – Jonathan Alfaro Apr 10 '21 at 03:19

2 Answers2

0

I believe what you're looking for is the JsonPropertyAttribute Required property:

public class MyDto
{
    [JsonProperty(Required = Required.Always)]
    public bool MyProp { get; set; }
}

This results in an exception when the JSON being deserialized does not contain the specified property (MyProp). For example, the following:

string json = "{\"MyProp\": true}";
MyDto myDto = JsonConvert.DeserializeObject<MyDto>(json);
Console.WriteLine(myDto.MyProp);

json = "{\"MyProp\": false}";
myDto = JsonConvert.DeserializeObject<MyDto>(json);
Console.WriteLine(myDto.MyProp);

json = "{}";
myDto = JsonConvert.DeserializeObject<MyDto>(json);
Console.WriteLine(myDto.MyProp);

Gives the result:

True
False
Run-time exception (line 17): Required property 'MyProp' not found in JSON. Path '', line 1, position 2.
devNull
  • 3,849
  • 1
  • 16
  • 16
0

You can validate the JSON using JSON Schema (Newtonsoft.Json.Schema) like this:

public class MyDto
{
    [JsonProperty(Required = Required.Always)]
    public bool MyProp { get; set; }
}


var generator = new JSchemaGenerator();
var schema = generator.Generate(typeof(MyDto));
var dto = JObject.Parse(@"{ 'MyProp': true }");
bool isValid = dto.IsValid(schema);
Console.WriteLine(isValid); // True

dto = JObject.Parse(@"{}");
isValid = dto.IsValid(schema);
Console.WriteLine(isValid); // False
rrmanzano
  • 11
  • 1