Model binding turns HTTP request values into .NET values and objects before an ASP.NET Core controller action or Razor Page handler runs. Declare a parameter—or, in a Razor Page, a bindable property—and work with C# data instead of parsing the request yourself. section 28.0 section 3.2.6
The shape of the target determines how values are assembled:
- A simple parameter takes one request value, converted to a type such as decimal, bool, or a date. section 28.3
- A complex parameter gets a new object whose public properties are bound individually. Nested objects use dotted names such as Category.Name; input tag helpers can generate those names with asp-for. section 28.4 section 28.4.2
- Repeated input names can populate an array. Indexed names such as Data[0] specify positions; sequence collections can also be binding targets. section 28.5.1 section 28.5.2
By default, binders search form data, the request body for controllers decorated with ApiController, route variables, then query strings, stopping when they find a suitable value. If a route supplies id, a competing query-string id does not win. Source attributes can direct binding to a particular part of the request. section 28.2 section 28.0
Binding is best effort, not a guarantee that the request supplied everything. A missing long argument can become 0; an unfilled complex-object property keeps its type’s default. Handle those cases with parameter defaults, nullable types, or code that tolerates missing data. Otherwise, the failure may surface later—for example, in a database query rather than in the binder. section 28.3.2 section 28.4
In Razor Pages, [BindProperty] binds a page-model property without duplicating it as a handler parameter. Its property name participates in matching form fields; GET binding requires SupportsGet = true. When binding handler parameters instead, check the generated input names: asp-for="Product.Name" produces Product.Name, not the name expected by a parameter called name. section 28.4.1 section 28.3.1
Validate a submitted RSVP
A [HttpPost] RsvpForm(GuestResponse guestResponse) action receives an object populated from form fields. Put [Required] and [EmailAddress] attributes on its properties, then check ModelState.IsValid: store the response and render a Thanks view when valid, or return the form when invalid. Make an unanswered attendance choice a nullable bool so [Required] can distinguish it from false. section 3.2.6 section 3.2.9
Do not treat an omitted form field as protection for a sensitive property: a client can submit its own value. Limit accepted properties with [Bind] or [BindNever], or receive data in a separate binding-target class containing only permitted fields. The latter prevents an unwanted ProductId from being copied into a new database entity. section 28.4.3 section 19.5.2
Listing 19.16 The ProductBindingTarget.cs file in the WebApp/Models folder
namespace WebApp.Models {
public class ProductBindingTarget {
public required string Name { get; set; }
public decimal Price { get; set; }
public long CategoryId { get; set; }
public long SupplierId { get; set; }
public Product ToProduct() => new Product() {
Name = this.Name, Price = this.Price,
CategoryId = this.CategoryId, SupplierId = this.SupplierId
};
}
}
The binding target accepts only the fields needed to create a product, then explicitly copies them into the application’s Product object. section 19.5.2


