Asp.Net Core Model Binding: Controlling The Binding Source

Asp.Net Core Model Binding has a set of attributes that gives us the ability to control from what source we want to receive the binding data. In this post I’m going to go through these attributes and show how and when you can use them.

Default Model Binder Behavior

The default behavior of model binder is that it first looks for data in posted form, if it didn’t find any it looks for data in routing value, and lastly it look for data in query strings. For example if we have a URL such as this Product/Detail/2?id=4, the number 2 will get binded, which is our route variable, but we can change these priorities by specifying exactly where we want our data to come from, Also these are not the only places that we can receive our data from. Asp.Net Core also gives us the ability to receive data from HTTP headers. In subsequent section I go over these attributes and explain their effects.

FromForm Attribute

This attribute is pretty straight forward, it causes the model binder to only use the incoming data from the submitted form.

public IActionResult Detail([FromForm] ProductViewModel productViewModel) => View(productViewModel);

FromRoute Attribute

This attribute cause the model binder to only bind the data that comes from route data:

public IActionResult Detail([FromRoute] int id) => View();

FromQuery Attribute

This attribute tells the model binder to only receive the data from query string, for example if we make a request with this url Product/Detail/2?id=4, the value 4 gets binded as opposed to the default behavior which causes the  value to be 2.

public IActionResult Detail([FromQuery] int id) => View();

FromHeader Attribute

This attribute helps us bind values that comes from HTTP request headers, as you can see in the image below.

But there is some problem that might come up when we want to bind to an incoming request header, and that is some of the headers are hyphenated values such as Accept-Language for example. In these circumstances we can use the name property of this attribute.

[FromHeader(Name = "Accept-Language")]

FromBody Attribute

This attribute cause the binder to bind the data from request body, for example when we make an AJAX request and send some JSON object as its data, we can use this attribute to bind the data.

$.get("/Product/Detail", { productViewModel: productViewModel },  function (data, textStatus, jqXHR) { },"json" );

public IActionResult Detail([FromBody] ProductViewModel productViewModel) => View(productViewModel);

FromServices Attribute

This attribute bind the specified value to the implementation that we configured in our IOC container.

public IActionResult Detail([FromServices] IPrintable printer) => View();

Bind And BindNever Attribute

BindNever attribute tells the model binder that it shouldn’t bind the specified attribute. As you can see in the code excerpt below, IsAdminUser never gets binded. This approach can be called black listing properties, which is not a good practice security wise. We’re better off white listing the attributes that we want to bind with Bind attribute as you can see in the second code excerpt.

Also It’s useful to say that we can use all of these attributes on properties of our class. We don’t have to use them directly in our action parameter list.

Summary

In this post, I’ve discussed how we can use Asp.Net Core’s model binding related attributes to help us have more control over the sources that we use to bind to our model.

Share...
 

Hamid Mosalla

Hi, I'm Hamid Mosalla, I'm a software developer, indie cinema fan and a classical music aficionado. Here I write about my experiences mostly related to web development and .Net.

 

4 thoughts on “Asp.Net Core Model Binding: Controlling The Binding Source

  1. Hey Hamid, I found your blog post through a google search. Do you know if it is possible to get a route to accept data from either Body or Query? I.e. public async Task Post([FromBody][FromQuery]DataModel model)

    Sometimes the data will come in as a POST body and sometimes in query.

    1. I tried but only one of them will work, but you can only decorate the action with [FromBody] and use syntax like /api/create-name?Name=Joel for query string, but it doesn’t going to bind to a view model by defining querystring this way, you have to define arguments explicitly, which I don’t think are going to be useful.

  2. Hi Hamid, I am new to .NET and writing an API which i want to pass parameters as query string. I use FromQuery bu it didn’t bind i had a lot of problems and after a lot search i found this post which solves my problem but still i dont understand : Quote from you “This attribute tells the model binder to only receive the data from query string, for example if we make a request with this url Product/Detail/2?id=4, the value 4 gets binded as opposed to the default behavior which causes the value to be 2.”

    Why i can’t use the url Product/Detail?id=4 instead of Product/Detail/2?id=4 which is unintuitive is there a way around it.
    Many Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *