- Home
- .NET tutorials
- FromQuery? FromForm? What do the .NET Web API attributes do?
FromQuery? FromForm? What do the .NET Web API attributes do?
Published: Sunday 28 May 2023
There are many From attributes including FromQuery
and FromForm
when adding a parameter to a controller's action in an ASP.NET Core Web API or MVC app. But what do these attributes do? And more importantly, how can we get them to work? We'll have a look at each one and give a C# code snippets to make it work.
FromQuery attribute
The FromQuery
attribute is used for getting a querystring parameter. We can add the FromQuery
attribute to an action parameter and by default, it will map the parameter name with the corresponding querystring name.
In this example, if we do a HTTP GET request for /api/from-api/from-query?page=4
, the page parameter would have a value of 4 and that value would be returned as part of the response.
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
[HttpGet("from-query")]
public IActionResult FromQuery([FromQuery] int page)
{
return Ok(new { page });
}
...
}
URL | Method | Parameter attribute, name & value |
---|---|---|
/api/from-api/from-query?page=4 |
GET | [FromQuery] int page = 4 |
When using the FromQuery
attribute, there is an optional Name
parameter that can be added. This is used when the action's parameter name is different to the querystring name.
C# coding challenges
For example, running /api/from-api/from-query?p=8
would map the page
parameter in the action to 8. This is because it's decorated with the FromQuery
attribute with a Name
of p
.
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpGet("from-query-with-name")]
public IActionResult FromQueryWithName([FromQuery(Name = "p")] int page)
{
return Ok(new { page });
}
...
}
URL | Method | Parameter attribute, name & value |
---|---|---|
/api/from-api/from-query-with-name?p=8 |
GET | [FromQuery(Name="p")] int page = 8 |
FromHeader attribute
The FromHeader
works in a similar way to the FromQuery
. For this, it maps the parameter to the corresponding request header based on the name.
An example of this is using authentication. If we are using JWT authentication in a Web API, we need to add an Authorization
header to the request. If we want to get the value of the Authorization
header, we can pass in a parameter with a name of authorization
and add the FromHeader
attribute to it.
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpGet("from-header")]
public IActionResult FromHeader([FromHeader] string authorization)
{
return Ok(new { authorization });
}
...
}
URL | Method | Headers | Parameter attribute, name & value |
---|---|---|---|
/api/from-api/from-header |
GET | Authorization: Bearer abcd |
[FromHeader] string authorization = "Bearer abcd" |
Once again, we can use the optional Name
parameter in FromHeader
if we wish to use a different parameter name to the header name.
For this, we have mapped the auth
parameter in the controller's action so it maps it to the Authorization
header in the request.
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpGet("from-header-with-name")]
public IActionResult FromHeaderWithName([FromHeader(Name = "Authorization")] string auth)
{
return Ok(new { auth });
}
...
}
URL | Method | Headers | Parameter attribute, name & value |
---|---|---|---|
/api/from-api/from-header-with-name |
GET | Authorization: Bearer abcd |
[FromHeader(Name="Authorization")] string auth = "Bearer abcd" |
FromForm attribute
The FromForm
works in a HTTP post request if the multipart/form-data
or x-www-url-encoded
content type is used.
Again, it will map the form field name with the parameter name. By using the Name
parameter in FromForm
, it will map it against the name of the form field that is specified in that.
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpPost("from-form")]
public IActionResult FromForm([FromForm] string name)
{
return Ok(new { name });
}
[HttpPost("from-form-with-name")]
public IActionResult FromFormWithName([FromForm(Name = "name")] string fullName)
{
return Ok(new { fullName });
}
...
}
URL | Method | Content-Type | Form values | Parameter attribute, name & value |
---|---|---|---|---|
/api/from-api/from-form |
POST | multipart/form-data |
name=David Grace |
[FromForm] string name = "David Grace" |
/api/from-api/from-form-with-name |
POST | multipart/form-data |
name=David Grace |
[FromForm(Name = "name")] string fullName = "David Grace" |
FromRoute attribute
The FromRoute
is used if a route attribute is used as part of the action. By adding FromRoute
to the action's parameter, it can get the value based on the name of the route attribute.
With the following example, there is a route attribute named {category}
. By default, the FromRoute
would map this attribute to a parameter name of category
. This can be overridden by specifying the name of the route attribute as part of the Name
parameter in the FromRoute
attribute.
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpGet("from-route/{category}")]
public IActionResult FromRoute([FromRoute] string category)
{
return Ok(new { category });
}
[HttpGet("from-route-with-name/{category}")]
public IActionResult FromRouteWithName([FromRoute(Name = "category")] string categoryName)
{
return Ok(new { categoryName });
}
...
}
URL | Method | Parameter attribute, name & value |
---|---|---|
/api/from-api/from-route/blazor |
GET | [FromRoute] string category = "blazor" |
/api/from-api/from-route-with-name/blazor |
GET | [FromRoute(Name = "category")] string categoryName = "blazor" |
FromServices attribute
The FromServices
attribute is the odd one out as it has nothing to do with a HTTP request. Instead, it allows us to use an action parameter to map a service from the IoC container using dependency injection.
In this instance, the FromServices
attribute is not required if the controller is mapped with the ApiController
attribute.
// IDateTimeService.cs
public interface IDateTimeService
{
DateTime GetUtcNow();
}
// DateTimeService.cs
public class DateTimeService : IDateTimeService
{
public DateTime GetUtcNow()
{
return DateTime.UtcNow;
}
}
// Program.cs
...
builder.Services.AddSingleton<IDateTimeService, DateTimeService>();
...
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpGet("from-services")]
public IActionResult FromServices(IDateTimeService dateTimeService)
{
return Ok(new { now = dateTimeService.GetUtcNow() });
}
...
}
However, without the ApiController
attribute, it throws an error. That is where we need to add the FromServices
attribute to the action's parameter so it knows to map the service from the IoC container and use dependency injection.
// FromMvcController.cs
[Route("api/from-mvc")]
public class FromMvcController : Controller
{
[HttpGet("from-services")]
public IActionResult FromServices([FromServices] IDateTimeService dateTimeService)
{
return Ok(new { now = dateTimeService.GetUtcNow() });
}
...
}
What is the ApiController attribute?
The ApiController
attribute is added to a controller when the actions within it are used to serve API responses.
They are configured with features and behaviour that help the developer experience for building APIs.
Some API specific behaviours including triggering an automatic HTTP 400 response if the ModelState
is not valid and problem details for error status codes.
There is more information about the ApiController
attribute on the Microsoft website.
FromBody attribute
The FromBody
attribute is used when using the application/json
content type and passing in JSON as part of the body.
However, this attribute only needs to use to be used when the ApiController
attribute is not present in the controller.
As a rule, the FromBody
can only be used for one parameter in an action. Therefore, in the likehood that there is more than one value being passed in the JSON body, each property needs to be added to a class, and this class is used as the type for the action parameter.
// Customer.cs
public class Customer
{
public string Forename { get; init; }
public string Surname { get; init; }
}
// FromApiController.cs
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
...
[HttpPost("from-body")]
public IActionResult FromBody(Customer customer)
{
return Ok(new { customer.Forename, customer.Surname });
}
}
// FromMvcController.cs
[Route("api/from-mvc")]
public class FromMvcController : Controller
{
...
[HttpPost("from-body")]
public IActionResult FromBody([FromBody]string forename)
{
return Ok(new { forename });
}
}
URL | Method | JSON | Controller attribute | Parameter attribute, name & value |
---|---|---|---|---|
/api/from-api/from-body |
POST | { "forename": "David", "surname": "Grace" } |
[ApiController] |
Customer customer = { Forename = "David", Surname = "Grace" } |
/api/from-mvc/from-body |
POST | { "forename": "David", "surname": "Grace" } |
[FromBody]Customer customer = { Forename = "David", Surname = "Grace" } |
See a demo of these attributes
Watch our video where we show you how to use these attributes. We'll show you an example for each attribute and execute it in Postman to show you the response.
In-addition, you can download the code example where you can download the ASP.NET Core web app used in this tutorial. In-addition, there is a Postman import script so you can execute the endpoints for yourself.