Web API Model Binding in ASP.NET MVC 6 (ASP.NET 5)

In ASP.NET 5, MVC and Web API have been merged into a single framework called MVC 6. If you are deep into Web API and MVC in the previous versions of ASP.NET, like me, it will take some time to get used to how binding works in MVC 6. Especially, if you are more into Web API in the recent past than MVC, like me, you will actually feel sad to see that the things you are so used to with Web API are all gone and it is different now : (.

With the good old ASP.NET Web API, the complex types are bound from the body, by default, and simple types are bound from URI and query string. This no longer holds good in Web API of MVC 6.

As the name indicates, MVC 6 is actually MVC, when it comes to binding. Well, it is MVC with Web API stuff bolted on, perhaps.

In Web API of MVC 6, binding is very ASP.NET MVC-ish. It does not matter you have a simple type or a complex type as parameter in the action method. It is bound from query string and form data in that order. If you want to bind from body (JSON or XML), you need to specify that using [FromBody]. Form data (application/x-www-form-urlencoded) will not be bound if you use [FromBody], since there is no formatter for form data. MVC 6 has input formatters for JSON and XML only, out of box.

Let’s see some examples now.

Action Method Request Message Binding Result
public void Post(string name) POST http://localhost:10725/api/values?name=23 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

name=34

name is set to 23, since query string wins over form data.
public void Post([FromForm]string name) POST http://localhost:10725/api/values?name=23 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

name=34

name is set to 34, since you are specifically asking for it through [FromForm].
public void Post(string name) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

name=34

name is set to 34. Despite being simple type, name is set from body by default, because the body is form data (one of MVC’s favorites).
public void Post([FromBody]string name) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

name=34

name is null, because for formatting body, we have only JSON and XML formatters.
public void Post([FromBody]string name) POST http://localhost:10725/api/values?name=20 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 17

{“name” : “john”}

Error, because JSON.NET is not happy with the JSON provided, which is for a complex type.
public void Post([FromBody]string name) POST http://localhost:10725/api/values?name=20 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 6

“john”

name is set to john, since we specifically ask for binding from body.
public void Post(Person p)

public class Person
{
  public string Name
    { get; set; }
  public int Age
    { get; set; }
}

POST http://localhost:10725/api/values?name=20 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 30

{“Name” : “John”, “Age” : 24 }

p.Name is set to 20 from query string. Despite being complex type, Person is being bound from query string, even though body with JSON is available.
public void Post(Person p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 30

{“Name” : “John”, “Age” : 24 }

p is not null but p.Name is null and p.Age is 0. Despite being complex type, body is not used for binding.
public void Post(Person p) POST http://localhost:10725/api/values?name=b&age=2 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 30

{“Name” : “John”, “Age” : 24 }

p.Name is set to b and p.Age is set to 2 from query string. Again, despite being complex type, Person is being bound from query string even if body is present. Query string rules!
public void Post([FromBody]Person p) POST http://localhost:10725/api/values?name=b&age=2 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 30

{“Name” : “John”, “Age” : 24 }

p.Name and p.Age are set to John and 24 from JSON. At last, Web API 2 like behavior but we need to ask for body to be used for binding using FromBody.
public void Post([FromBody]Person p, Person q) POST http://localhost:10725/api/values?name=b&age=2 HTTP/1.1
Content-Type: application/json
Host: localhost:10725
Content-Length: 30

{“Name” : “John”, “Age” : 24 }

p is bound from JSON and q is bound from query string.
public void Post(Person p) POST http://localhost:10725/api/values?name=b&age=2 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 16

name=john&age=24

p.Name is set to b and p.Age is set to 2. Again, query string rules!
public void Post(Person p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 16

name=john&age=24

p.Name is set to john and p.Age is set to 24. This is similar to Web API in that complex type is bound from body. In fact, this is only a coincidence. As far MVC is concerned, it is doing MVC binding using the form data.
public void Post([FromBody]Person p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 16

name=john&age=24

p is null, because form data cannot be bound using the formatters available: JSON and XML. We are specifically asking for body but MVC 6 cannot read form data using the formatters.
public void Post([FromForm]Person p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 16

name=john&age=24

p.Name is set to john and p.Age is set to 24. MVC 6 is happy because now we are asking the body to be treated as form data.
public void Post(List<Person> p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 52

p[0].name=john&p[0].age=24&p[1].name=joe&p[1].age=28

p(0).Name is john
p(0).Age is 24
p(1).Name is joe
p(1).Age is 28
MVC all over the place!
public void Post(List<string> p) POST http://localhost:10725/api/values HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

p=1&p=2

p(0) = 1
p(1) = 2
public void Post(List<string> p) POST http://localhost:10725/api/values?p=20&p=30 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:10725
Content-Length: 7

p=1&p=2

p(0) = 20
p(1) = 30
Advertisements

10 thoughts on “Web API Model Binding in ASP.NET MVC 6 (ASP.NET 5)

  1. Thank you for the list, this does seem completely backwards though! All I want to do is post JSON data back to a controller and get those values.

    – I dont want to use query parameters (this isnt a right fit for POST data)
    – I dont want to have to create a model solely to accept this data (a waste of time / effort)
    – I’d rather not have to convert my JSON data into form-like data just to send it back

    ARGH!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s