Data and Formats · Lesson 16

Required JSON presence is not nonnull content

Check presence, nullability, and business meaning as separate contracts.

How it works

A required property can tell System.Text.Json that a member must appear in the payload. Deserializing an empty object into Profile therefore fails with JsonException. The reader cannot silently produce the same result as a complete profile while omitting the declared required member.

The second payload supplies Name explicitly as null. Under the ordinary options used here, the required-presence contract is satisfied even though the resulting Name is null. The final true highlights the difference between presence and a valid nonnull string. The compiler's nonnullable annotation does not replace every runtime boundary check.

A complete input policy may need several rules: the property exists, its value is not null, its text is not blank, and its length or allowed characters satisfy the application. Apply those checks deliberately. Newer serializer options can enforce additional nullability rules, but they should be selected and tested rather than assumed from a type declaration alone.

Do not demonstrate required presence by treating every deserialization exception as a missing-name error. Malformed JSON, incompatible value kinds, and other contract failures can also produce JsonException. A useful boundary should preserve enough information to explain the actual rejected input without depending on brittle exact framework exception text.

Practice with missing Name, null Name, an empty string, whitespace, and a valid display name. Build a validation function that clearly distinguishes structural parsing failure from an accepted model whose domain values are invalid. Keep the valid profile construction path simple and explicit.

Finally, compare C# object initialization with JSON deserialization. Both can use required-member metadata, but they occur at different boundaries and have different failure mechanisms. A trustworthy data pipeline does not rely on one keyword to guarantee every invariant; it documents which layer establishes presence, type compatibility, null handling, and meaningful domain content.

A working example

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

try { JsonSerializer.Deserialize<Profile>("{}"); }
catch (JsonException) { Console.WriteLine("missing required"); }
var profile = JsonSerializer.Deserialize<Profile>("""{"Name":null}""")!;
Console.WriteLine(profile.Name is null);
class Profile { public required string Name { get; init; } }

Expected output

missing required
True
Try this
A required property must be present; validate whether its supplied value is meaningful.