Model Binding : Passing Data from View to Controller

In this Model binding in ASP.NET Core article, we will learn How to pass data from View to Controller.  We learn what is Model binding is and how it works. The ASP.NET core allows us to bind data from various binding sources like HTML Forms using [FromForm], Route Values using [FromRoute], Query string using [FromQuery], Request body using [FromBody] and From Request Header using [FromHeader]. We will look at all these in this chapter

Here is the link to previous tutorials

  1. Model and ViewModel
  2. Passing ViewModel from Controller to View
  3. Building Forms in Views
  4. Creating Strongly typed Views
  5. Using Tag Helpers to Create Forms

What is Model Binding

The Model binding is the process of mapping the data posted over an HTTP request to the parameters of the action method in the Controller.

The HTTP Request can contain data in various formats. The data can contain in the HTML form fields. It could be part of the route values. It could be part of the query string or it may contain in the body of the request.

ASP.NET Core model binding mechanism allows us easily bind those values to the parameters in the action method. These parameters can be of the primitive type or complex type.

Getting Form Data in Controller

In the tutorial on Tag Helpers, we created a simple Form, which accepted the Product detail. When the user clicked on the submit button it posted the data to the create controller action method.

In the above project, we created a ProductEditModel object, which contains the details of the product that needs to be created or edited

A form is created to which contains three form fields. Name, Rate and Rating.

The Create action method in the HomeController.

On the submission of the above form, the values in the form fields are automatically mapped to the ProductEditModel object of the action method of the controller.

This automatically happens behind the scene by a Process called Model Binding. The Model binder looks for a match in the form fields, Route Values and query strings.

How Model Binding works

The image below illustrates how model binding works.

Model Binding

When the user clicks on the Submit button a Post request is sent to the server along with the Form Data, Query String, Route Parameters etc.

The MVCRouteHandler of the Routing Engine handles the incoming request and is responsible for invoking the action method create.

The Model binder kicks in just before the action method invocation. It looks for a match in the form data, query strings, and request parameters in the HTTP Request data.

Then, It tries to bind the values to the action parameter by Name.

For Example, the “name” form field is mapped to the “name” property of the ProductEditModel. Rate Form field is mapped to the Rate Property and henceforth.

Getting Form data from view to controller

For the Binding to work correctly

  • The Property Name must match with the Request data
  • Properties must be defined as public settable

Model Binder

The Model binder is responsible to populate the action method parameter. The Model Binder is created by the model binder provider.

The Model binder must implement the provider interface is IModelBinderProvider.

Which, means you can create your own Model binder or extend the existing one by implementing the  IModelBinderProvider. The customer model binder must be registered in the ModelBinderProviders collection at the startup.cs as follows.

ModelState

If Model binder fails to bind the incoming Request data to the corresponding model property, then it does not throw any error but fails silently. But it updates ModelState object with the list of errors and sets the isValid property to false.

Hence, checking for ModelState.isValid tells us whether the model binding succeeded or not.

For Example, in the above example clicking on the submit button without entering any data in any of the fields will result in validation failure and hence the ModelState.isValid becomes false.

Life without model binding

Before further exploring the Model binding, we need to understand how you can access data without using the model binding.

Accessing the HTML Forms directly

To do that we need to access the Request object to access the values the data.

Open the code, which we created in the previous tutorial,

Add the new action method NoModelBinding action method

And change to

Accessing the query string directly

Similarly, you can access the query string values directly using the Request.Query collection, which is parsed from the Query String.

For Example Request.Query[“id”].ToString() returns the value of id query string.

The Request.QueryString.HasValue will let you know if the Query string is present in the URL and Request.QueryString.Value will return the raw query string.

Accessing the Request Headers directly

Similarly you can use the Request.Headers collection to access the values present the HTTP Headers

Accessing the Route Data directly

To Access the route you need to Override the OnActionExecuting method as shown below

As you can see it takes a lot of code to access the values posted over HTTP Request. The ASP.NET Core Model binding hides all those intricacies for us.

Model Binding Sources

As mentioned earlier, the model binder looks for the data from the various data sources. Here is the list of data sources in the order that model binding looks through them

  • HTML Form Values
  • Route Values
  • Query Strings

The Model binder can also look for the data from the following sources also, but to do that we need to specify the binding source explicitly.

  • Request Body
  • Request Header
  • Services

Getting data from Form and query string

Let us try to bind action parameter to both Form and query string. FormAndQuery action method as shown below

Note that the Action Method FormAndQuery takes two arguments name and ProductEditModel.

Next, create the view FormAndQuery and the following code.

The form has a name field. We are also sending name=test as the query string to the controller action

In the above example, the parameter “name” appears twice as the part of the Form and also part of the query string

When this form is submitted, the “name” parameter is always mapped to the Form field and not to the query string.

That is because the Model binder always uses the following order to map the data source fields to the parameter. And the first match wins.

  1. Form Values
  2. Route Values
  3. Query strings

Since the Form Values has a name field, the name parameter is always populated by it.

We can change this behaviour by decorating the name parameter by using the [FromQuery] attribute.

Apply the [FromQuery] attribute to the name parameter as shown below

public IActionResult FormAndQuery([FromQuery] string name,ProductEditModel model)

Now, if you submit the form, the name parameter gets the value from the query string, while productEditModel correctly populated from the form values

Controlling the Binding Source

In the previous example, we used [FromQuery] attribute to force model binder to change its default behaviour and use query string as the source for binding.

The ASP.NET Core gives us several such attributes to control and choose from what source we want to receive the binding data

  1. [FromForm]
  2. [FromRoute]
  3. [FromQuery]
  4. [FromBody]
  5. [FromHeader]
  6. [FromServices]

[FromForm]

The [FromForm] forces the model binder to bind the parameter to the fields of the HTML Forms.

[FromRoute]

The [FromRoute] forces the model binder to bind that parameter to Route data from the current request.

Let us see how to use it with a live example.

Create a FromRoute action method, which accepts the id and ProductEditModel

We have two id parameter. The MVC default route has Id Parameter, which is optional. The ProductEditModel also has an id property

Create FromRoute view

Note that we are invoking the controller action by using the “test” as the route value.

Now, when you submit the form, the id parameter is always mapped to the id Form field and not from the route value.

Now Open the HomeController and apply [FromRoute] Attribute on the id Parameter as shown below.

Now, when you submit the form the id is populated with “test”.

Binding Query string using [FromQuery]

[FromQuery] forces the model binder to bind the parameter to the value obtained from the query string.

Binding to Request body Using [FromBody]

[FromBody] forces the model binder to bind a parameter to data from the request body. The formatter is selected based on the content-type of the request.

The data in the request body come in the variety of formats including JSON, XML and many others. The Model binder looks at the content-type header to select the formatter to parse the data contained in the request body.

For example, when the content-type is “application/json”, the model binder uses the JsonInputFormatter class to parse the request body and map it to the parameter.

Binding from Request Header using [FromHeader]

[FromHeader] maps the request header values to the action parameter.

Disabling Binding with [BindNever]

The Tells the model binder to never bind to the Property.

For Example,

Now, model binder ignore the Rating Property, even if the form has Rating field.

Forcing Binding with [BindRequired]

This is exactly opposite of BindNever. The field marked with BindRequired must always present in the form field and binding must occur, otherwise will Modelstate.isValid marked as false.

Summary

We looked at how you can pass data from view to controller using Model Binder, The Model binder automatically binds the fields to Model Property behind the scene. You can modify the default behaviour of the Model binder by using the various attributes like [FromForm], [FromQuery], [FromBody],[FromRoute],[FromHeader] , [FromServices] [BindNever] & [BindRequired] etc.

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top