ASP.NET Core 2.0 MVC Model Binding

Problem

How does model binding work in ASP.NET Core MVC.

Solution

In an empty project, change Startup class to add services and middleware for MVC.

Add the following code to HomeController, demonstrating binding of simple types.

Add the following code to HomeController, demonstrating binding of complex types.

Add the following code to HomeController, demonstrating binding of collections.

Add the following code to HomeController, demonstrating binding from multiple sources.

Discussion

In a previous post on Routing, I showed how MVC maps URLs to Controller and actions to execute. We touched on the topic of the model binding mechanism through which MVC binds routing template tokens to action parameters.

Routing middleware deconstructs the HTTP request into RouteData class and then binds its values to action parameters by name. Below is a screenshot showing the Keys and Values contained within RouteData class.


The action parameters can be simple or complex types. For complex types, model binding uses reflection to bind the data using the dot (.) convention. The type must contain a default constructor and public writable properties. See how query string values populate a complex type:


Note that failure in binding doesn’t throw an exception. Also, the process of binding stops as soon as a match is found for a parameter (see Multiple Sources section below).

Binding with Attributes

Attributes on action parameters can be used to override the default binding behavior:

  • Override binding behavior

    • [BindRequired]: add model state error if binding fails
    • [BindNever]: ignore the binding of parameter

  • Override binding source

    • [FromHeader]: use HTTP header
    • [FromQuery]: use URL query string
    • [FromRoute]: use routing values
    • [FromForm]: use form values (via HTTP POST)
    • [FromServices]: inject value using dependency injection
    • [FromBody]: use HTTP request body, based on configured formatter (e.g. JSON, XML). Only one action parameter can have this attribute.

  • Supply custom binding

    • [ModelBinder]: provide custom model binder
Binding Behaviour

When binding attributes are not supplied, the default behavior is,

  • Simple Types: binding source can be route values, query string, and form data.
  • Complex Types: binding source can be query string and form data.
Binding Header

When binding to HTTP headers, few points to note are -

For complex types, the [FromHeader] attribute is applied to the type’s properties. If the HTTP header contains characters illegal for variable names, they can be supplied via attributes Name property.


For simple types.


Binding Body

HTTP response body can be read into a complex type. By default, JsonInputFormatter class is used to handle binding of the request body. The input formatters are used based on the Content-Type property of HTTP request header. Below is a sample request with JSON body.


In order to use XML as input, formatters modify ConfigureServices.

Now, in addition to JSON, you could send XML in request body (remember to change the Content-Type to application/xml).


Binding Collections

Binding works with collection too.

Multiple Sources

MVC tries to bind the data from other parts of HTTP request in the following sequence.

  1. Form: form data submitted via HTTP POST
  2. Route: route values deconstructed by routing middleware
  3. Query: query string segment of URL


Source Code

GitHub