The HttpRequest class provides access to the raw request data through the QueryString, Headers, and
Forms properties. However, whenever possible it is recommended to use model binding instead of directly accessing the input data.
Both ASP.Net MVC implementations - Core and Framework - support model binding in a comparable fashion. Model binding streamlines the process by automatically aligning data from HTTP requests with action method parameters, providing numerous benefits compared to manually parsing raw incoming request data:
Model binding simplifies the code by automatically mapping data from HTTP requests to action method parameters. You don’t need to write any code to manually extract values from the request.
Model binding provides type safety by automatically converting the incoming data into the appropriate .NET types. If the conversion fails, the
model state becomes invalid, which you can easily check using ModelState.IsValid.
With model binding, you can easily apply validation rules to your models using data annotations. If the incoming data doesn’t comply with these rules, the model state becomes invalid.
Model binding helps protect against over-posting attacks by only including properties in the model that you explicitly bind using the
[Bind] attribute or by using view models that only contain the properties you want to update.
By using model binding, your code becomes cleaner, easier to read, and maintain. It promotes the use of strongly typed views, which can provide compile-time checking of your views.
Request.Form, Request.Form.Files, Request.Headers, Request.Query and Request.RouteValues are keyed
collections that expose data from the incoming HTTP request:
Request.Form - application/x-www-form-urlencoded form data from the HTTP request body Request.Form.Files - multipart/form-data file data from the HTTP request body Request.Headers - HTTP Header values Request.Query - URL parameter values Request.RouteValues - Values extracted from the path portion of the URL
Model binding can bind these keyed collections to
To replace the keyed collection access, you can:
| Replace | with parameter binding | or complex type binding | or route binding |
|---|---|---|---|
|
optional |
optional |
|
|
|||
|
|
|
|
|
optional |
optional |
|
|
optional |
optional |
The Model Binding in ASP.NET Core article describes the mechanisms, conventions, and customization options for model binding in more detail. Route-based binding is described in the Routing to controller actions in ASP.NET Core document.
public IActionResult Post()
{
var name = Request.Form["name"]; // Noncompliant: Request.Form
var birthdate = DateTime.Parse(Request.Form["Birthdate"]); // Noncompliant: Request.Form
var locale = Request.Query.TryGetValue("locale", out var locales)
? locales.ToString()
: "en-US"; // Noncompliant: Request.Query
// ..
}
public record User
{
[Required, StringLength(100)]
public required string Name { get; init; }
[DataType(DataType.Date)]
public DateTime? Birthdate { get; init; }
}
public IActionResult Post(User user, [FromHeader] string origin, [FromQuery] string locale = "en-US")
{
if (ModelState.IsValid)
{
// ...
}
}
Model binding in ASP.NET Core MVC and ASP.NET MVC 4.x works by automatically mapping data from HTTP requests to action method parameters. Here’s a step-by-step breakdown of how it works:
ModelState.Errors collection. You can check ModelState.IsValid in your action method to see if any
errors occurred during model binding. ModelState.IsValid is
false, you can handle the errors in your action method and return an appropriate response. See the links in the Resources section for more information.
Request.Form and Request.QueryString are keyed collections
that expose data from the incoming HTTP request:
Request.Form - application/x-www-form-urlencoded form data from the HTTP request body Request.QueryString - URL parameter values Model binding can bind these keyed collections to
To replace the keyed collection access, you can:
| Replace | with parameter binding | or complex type binding |
|---|---|---|
|
optional |
optional |
|
optional |
property name must match query parameter key |
public ActionResult Post()
{
var name = Request.Form["name"]; // Noncompliant: Request.Form
Debug.WriteLine(Request.Form[0]); // Compliant: Binding by index is not supported.
var birthdate = DateTime.Parse(Request.Form["Birthdate"]); // Noncompliant: Request.Form
var cultureName = Request.QueryString["locale"] ?? "en-US"; // Noncompliant: Request.QueryString
// ..
}
public class User
{
[Required, StringLength(100)]
public string Name { get; set; }
[DataType(DataType.Date)]
public DateTime? Birthdate { get; set; }
}
public ActionResult Post(User user, [Bind(Prefix = "locale")] string cultureName = "en-US")
{
if (ModelState.IsValid)
{
// ...
}
}
public IActionResult Post()
{
var origin = Request.Headers[HeaderNames.Origin]; // Compliant: Access via non-constant field
var nameField = "name";
var name = Request.Form[nameField]; // Compliant: Access via local
var birthdate = DateTime.Parse(Request.Form["Birthdate"]); // Compliant: Access via constant and variable keys is mixed.
// Model binding would only work partially in the method, so we do not raise here.
return Ok();
// ..
}
Model binding in ASP.NET Core MVC and ASP.NET MVC 4.x works by automatically mapping data from HTTP requests to action method parameters. Here’s a step-by-step breakdown of how it works:
ModelState.Errors collection. You can check ModelState.IsValid in your action method to see if any
errors occurred during model binding. ModelState.IsValid is
false, you can handle the errors in your action method and return an appropriate response. See the links in the Resources section for more information.