|
1 | 1 | --- |
2 | 2 | title: Require properties for deserialization |
3 | 3 | description: "Learn how to mark properties as required for deserialization to succeed." |
4 | | -ms.date: 09/21/2022 |
| 4 | +ms.date: 10/22/2024 |
5 | 5 | no-loc: [System.Text.Json, Newtonsoft.Json] |
6 | 6 | --- |
7 | 7 | # Required properties |
8 | 8 |
|
9 | | -Starting in .NET 7, you can mark certain properties to signify that they must be present in the JSON payload for deserialization to succeed. If one or more of these required properties is not present, the <xref:System.Text.Json.JsonSerializer.Deserialize%2A?displayProperty=nameWithType> methods throw a <xref:System.Text.Json.JsonException>. |
| 9 | +You can mark certain properties to signify that they must be present in the JSON payload for deserialization to succeed. Similarly, you can set an option to specify that all non-optional constructor parameters are present in the JSON payload. If one or more of these required properties is not present, the <xref:System.Text.Json.JsonSerializer.Deserialize%2A?displayProperty=nameWithType> methods throw a <xref:System.Text.Json.JsonException>. |
10 | 10 |
|
11 | 11 | There are three ways to mark a property or field as required for JSON deserialization: |
12 | 12 |
|
13 | | -- By adding the [required modifier](../../../csharp/language-reference/keywords/required.md), which is new in C# 11. |
14 | | -- By annotating it with <xref:System.Text.Json.Serialization.JsonRequiredAttribute>, which is new in .NET 7. |
15 | | -- By modifying the <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType> property of the contract model, which is new in .NET 7. |
| 13 | +- By adding the [`required` modifier](../../../csharp/language-reference/keywords/required.md). |
| 14 | +- By annotating it with <xref:System.Text.Json.Serialization.JsonRequiredAttribute>. |
| 15 | +- By modifying the <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType> property of the contract model. |
16 | 16 |
|
17 | | -From the serializer's perspective, these two demarcations are equivalent and both map to the same piece of metadata, which is <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType>. In most cases, you'd simply use the built-in C# keyword. However, in the following cases, you should use <xref:System.Text.Json.Serialization.JsonRequiredAttribute> instead: |
| 17 | +To specify that all non-optional constructor parameters are required for JSON deserialization, set the <xref:System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters?displayProperty=nameWithType> option (or, for source generation, <xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute.RespectRequiredConstructorParameters> property) to `true`. For more information, see the [Non-optional constructor parameters](#non-optional-constructor-parameters) section. |
| 18 | + |
| 19 | +From the serializer's perspective, the C# `required` modifier and [`[JsonRequired]`](xref:System.Text.Json.Serialization.JsonRequiredAttribute) attribute are equivalent, and both map to the same piece of metadata, which is <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType>. In most cases, you'd simply use the built-in C# keyword. However, in the following cases, you should use <xref:System.Text.Json.Serialization.JsonRequiredAttribute> instead: |
18 | 20 |
|
19 | 21 | - If you're using a programming language other than C# or a down-level version of C#. |
20 | 22 | - If you only want the requirement to apply to JSON deserialization. |
21 | 23 | - If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#metadata-based-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time. |
22 | 24 |
|
23 | 25 | The following code snippet shows an example of a property modified with the `required` keyword. This property must be present in the JSON payload for deserialization to succeed. |
24 | 26 |
|
25 | | -```csharp |
26 | | -using System.Text.Json; |
| 27 | +:::code language="csharp" source="snippets/required-properties/RequiredProperties.cs" id="Keyword"::: |
27 | 28 |
|
28 | | -// The following line throws a JsonException at run time. |
29 | | -Console.WriteLine(JsonSerializer.Deserialize<Person>("""{"Age": 42}""")); |
| 29 | +Alternatively, you can use <xref:System.Text.Json.Serialization.JsonRequiredAttribute>: |
30 | 30 |
|
31 | | -public class Person |
32 | | -{ |
33 | | - public required string Name { get; set; } |
34 | | - public int Age { get; set; } |
35 | | -} |
36 | | -``` |
| 31 | +:::code language="csharp" source="snippets/required-properties/RequiredProperties.cs" id="Attribute"::: |
37 | 32 |
|
38 | | -Alternatively, you can use <xref:System.Text.Json.Serialization.JsonRequiredAttribute>: |
| 33 | +It's also possible to control whether a property is required via the contract model using the <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType> property: |
39 | 34 |
|
40 | | -```csharp |
41 | | -using System.Text.Json; |
| 35 | +:::code language="csharp" source="snippets/required-properties/RequiredProperties.cs" id="ContractModel"::: |
| 36 | + |
| 37 | +## Non-optional constructor parameters |
42 | 38 |
|
43 | | -// The following line throws a JsonException at run time. |
44 | | -Console.WriteLine(JsonSerializer.Deserialize<Person>("""{"Age": 42}""")); |
| 39 | +Prior to .NET 9, constructor-based deserialization treated all constructor parameters as optional, as the following example shows: |
45 | 40 |
|
46 | | -public class Person |
47 | | -{ |
48 | | - [JsonRequired] |
49 | | - public string Name { get; set; } |
50 | | - public int Age { get; set; } |
51 | | -} |
| 41 | +```csharp |
| 42 | +var result = JsonSerializer.Deserialize<Person>("{}"); |
| 43 | +Console.WriteLine(result); // Person { Name = , Age = 0 } |
| 44 | +
|
| 45 | +record Person(string Name, int Age); |
52 | 46 | ``` |
53 | 47 |
|
54 | | -It's also possible to control whether a property is required via the contract model using the <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.IsRequired?displayProperty=nameWithType> property: |
| 48 | +Starting in .NET 9, you can set the <xref:System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters> flag to treat non-optional constructor parameters as required. |
55 | 49 |
|
56 | | -```csharp |
57 | | -var options = new JsonSerializerOptions |
58 | | -{ |
59 | | - TypeInfoResolver = new DefaultJsonTypeInfoResolver |
60 | | - { |
61 | | - Modifiers = |
62 | | - { |
63 | | - static typeInfo => |
64 | | - { |
65 | | - if (typeInfo.Kind != JsonTypeInfoKind.Object) |
66 | | - return; |
67 | | - |
68 | | - foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties) |
69 | | - { |
70 | | - // Strip IsRequired constraint from every property. |
71 | | - propertyInfo.IsRequired = false; |
72 | | - } |
73 | | - } |
74 | | - } |
75 | | - } |
76 | | -}; |
77 | | - |
78 | | -// Deserialization now succeeds even though the Name property isn't in the JSON payload. |
79 | | -JsonSerializer.Deserialize<Person>("""{"Age": 42}""", options); |
| 50 | +:::code language="csharp" source="snippets/required-properties/RequiredProperties.cs" id="RequiredConstrParams"::: |
| 51 | + |
| 52 | +### Feature switch |
| 53 | + |
| 54 | +You can turn on the `RespectRequiredConstructorParameters` setting globally using the `System.Text.Json.Serialization.RespectRequiredConstructorParametersDefault` feature switch. Add the following MSBuild item to your project file (for example, *.csproj* file): |
| 55 | + |
| 56 | +```xml |
| 57 | +<ItemGroup> |
| 58 | + <RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.RespectRequiredConstructorParametersDefault" Value="true" /> |
| 59 | +</ItemGroup> |
80 | 60 | ``` |
| 61 | + |
| 62 | +The `RespectRequiredConstructorParametersDefault` API was implemented as an opt-in flag in .NET 9 to avoid breaking existing applications. If you're writing a new application, it's highly recommended that you enable this flag in your code. |
0 commit comments