200

Why are the FromBody and FromUri attributes needed in ASP.NET Web API`?

What are the differences between using the attributes and not using them?

user247702
  • 23,641
  • 15
  • 110
  • 157
Rajneesh
  • 2,009
  • 2
  • 12
  • 6
  • 15
    Just to give a hint on when it might be useful to use the [FromBody] annotation: It is for example poor practice to send static credentials such as username/password as parameters encoded within the URL. Even though SSL-encryption might prevent that a third party may gain reading access to the parameters within the URL, it still remains poor practice, as these credentials might be stored in browser logs and equals, which is definitely not desired. In such a case, one could use the [FromBody] annotation, to force the storage of a parameter within the body of the HTTP message, introducing a high – Chris Feb 16 '16 at 10:28

4 Answers4

237

When the ASP.NET Web API calls a method on a controller, it must set values for the parameters, a process called parameter binding.

By default, Web API uses the following rules to bind parameters:

  • If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string.

  • For complex types, Web API tries to read the value from the message body, using a media-type formatter.

So, if you want to override the above default behaviour and force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter.

So, to answer your question, the need of the [FromBody] and [FromUri] attributes in Web API is simply to override, if necessary, the default behaviour as described above. Note that you can use both attributes for a controller method, but only for different parameters, as demonstrated here.

There is a lot more information on the web if you google "web api parameter binding".

Community
  • 1
  • 1
djikay
  • 10,450
  • 8
  • 41
  • 52
  • 6
    @user3510527: You don't have to use these attributes if you don't want to, as long as you follow the default behaviour. If you want to change the default behaviour, then you need to use them. – djikay Jul 08 '14 at 13:15
  • 1
    if it is doing its default behavior, then why we need to ovveride and what benefits we will get if we mentioned this attribute ? – Rajneesh Jul 09 '14 at 06:32
  • 1
    @user3510527 You don't *need* to override. You can just use the default behaviour. One example where someone might want to override is if they want to supply a simple integer in the body of the request because, by default, it will expect to find it in the URI. Basically, you can just leave the default behaviour if you want or you can override, it's just an option you have. I don't understand what the confusion is. – djikay Jul 09 '14 at 11:01
  • 8
    I wonder if one could make an attribute called `JustGetIt` which serves the same purpose of adding multiple attributes like `[FromBody, FromQuery]` etc – The Muffin Man Jul 15 '16 at 16:51
137

The default behavior is:

  1. If the parameter is a primitive type (int, bool, double, ...), Web API tries to get the value from the URI of the HTTP request.

  2. For complex types (your own object, for example: Person), Web API tries to read the value from the body of the HTTP request.

So, if you have:

  • a primitive type in the URI, or
  • a complex type in the body

...then you don't have to add any attributes (neither [FromBody] nor [FromUri]).

But, if you have a primitive type in the body, then you have to add [FromBody] in front of your primitive type parameter in your WebAPI controller method. (Because, by default, WebAPI is looking for primitive types in the URI of the HTTP request.)

Or, if you have a complex type in your URI, then you must add [FromUri]. (Because, by default, WebAPI is looking for complex types in the body of the HTTP request by default.)

Primitive types:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

Complex types:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

This works as long as you send only one parameter in your HTTP request. When sending multiple, you need to create a custom model which has all your parameters like this:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

From Microsoft's documentation for parameter binding in ASP.NET Web API:

When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object). At most one parameter is allowed to read from the message body.

This should work:

public HttpResponseMessage Post([FromBody] string name) { ... }

This will not work:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

The reason for this rule is that the request body might be stored in a non-buffered stream that can only be read once.

tedi
  • 6,350
  • 5
  • 52
  • 67
  • 12
    "At most one parameter is allowed to read from the message body" was especially helpful information – Ryan Aug 06 '19 at 19:01
  • This is not true. I use an int Id in the url and an object in the body and it works just fine. I do have [FromBody] on my objects though, so that may have been required. – PRMan Nov 23 '21 at 16:40
23

Just addition to above answers ..

[FromUri] can also be used to bind complex types from uri parameters instead of passing parameters from querystring

For Ex..

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

Can be called like:

http://localhost/api/values/47.678558/-122.130989
Frederik Struck-Schøning
  • 12,981
  • 8
  • 59
  • 68
Utkarsh Patel
  • 305
  • 2
  • 8
21

When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object).

At most one parameter is allowed to read from the message body. So this will not work:

// Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

The reason for this rule is that the request body might be stored in a non-buffered stream that can only be read once.

Please go through the website for more details: https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Pang
  • 9,564
  • 146
  • 81
  • 122
user5166729
  • 219
  • 2
  • 2