A nullable type permits null as well as an ordinary value. Append `?` to the type: `string?` can hold a string or null, while `string` is declared non-nullable. With null state analysis enabled, the compiler warns when code assigns null to a non-nullable variable or accesses a nullable reference without checking it first. section 5.4
In an ASP.NET Core action, a nullable parameter can distinguish an omitted request value from a value the user actually supplied. An `Index(long? id)` action receives null when the request contains no suitable `id`; a supplied zero remains zero. That distinction matters when zero should be queried rather than treated as though no ID was supplied. section 28.3.2
Choose a product when no ID is supplied
In `Controllers/FormController.cs`, use `public async Task<IActionResult> Index(long? id)` and query with `.FirstOrDefaultAsync(p => id == null || p.ProductId == id)`. Request `/controllers/form` to select the first database object. Request `/controllers/form/index/0` to query for ID zero instead; if none matches, the query returns null. The point is not to make zero special—it is to keep “missing” separate from “provided.” section 28.3.2
Listing 28.9. A nullable parameter in the FormController.cs file in the Controllers folder
...
public async Task<IActionResult> Index(long? id) {
ViewBag.Categories = new SelectList(context.Categories,
"CategoryId", "Name");
return View("Form", await context.Products.Include(p => p.Category)
.Include(p => p.Supplier)
.FirstOrDefaultAsync(p => id == null || p.ProductId == id));
}
...
See the complete controller-action change, including the nullable parameter and its Entity Framework Core query. section 28.3.2
Put the question mark on the part that may be null:
- `Product?[]`: the array itself is non-nullable, but an element may be null. section 5.4.3
- `Product[]?`: the array may be null, but its elements are non-nullable. section 5.4.3
- `Product?[]?`: both the array and its elements may be null. section 5.4.3
Nullable model properties also preserve the difference between an unanswered form field and an answer. For an RSVP form, `bool? WillAttend` can be true, false, or null. If the user makes no selection, null lets `[Required]` report a validation error during model binding; an ordinary `bool` would offer only true or false. section 3.2.9


