- 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.
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.
Related tutorials
Why Blazor Wasm is the best choice for API integration
Why you should use Blazor WebAssembly over JavaScript frameworks for API integration. Examples of integrating a CRUD API in Blazor Wasm.