Actions are each of the methods within a controller, which are responsible for responding to a specific HTTP request.
Each controller will contain one or more actions, which will be associated with each type of request (GET, POST, PUT, DELETE, …)
Internally, actions are nothing more than public methods within the controller. They can receive parameters and return different types of responses.
Main features of action methods
- Public: Action methods must be public for the framework to invoke them.
- Non-static: They cannot be static, as they must belong to an instance of the controller.
- Associated with routes: Each action method is associated with a specific route through routing.
- Can accept parameters: They can accept parameters passed through the URL, the request body, or headers.
Mapping actions to HTTP requests
For the action to work correctly, we need to map (associate) each action to an HTTP request. We can do this in two ways:
The most common (and recommended) way is to use attributes to define how actions handle HTTP requests.
These attributes are placed above the action methods and specify the HTTP verb they handle, as well as other configurations.
Attribute | Description |
---|---|
[HttpGet] | Handles HTTP GET requests |
[HttpPost] | Handles HTTP POST requests |
[HttpPut] | Handles HTTP PUT requests |
[HttpDelete] | Handles HTTP DELETE requests |
[HttpPatch] | Handles HTTP PATCH requests |
For example,
[HttpPost("create")]
public IActionResult CreateProduct([FromBody] Product product) { ... }
It is the recommended option
The other option (not recommended) is to use method naming conventions. ASP.NET automatically maps:
Get()
→ GETPost()
→ POSTPut()
→ PUTDelete()
→ DELETE
For example like this,
public class ProductsController : ControllerBase
{
// automatically mapped to GET /products
public IActionResult Get() { ... }
}
Do not use this unless you encounter it in a project that is not yours, and you have no other choice.
Example with attributes
Let’s make it easier with a complete example. I will make the example only with attributes because it is the one you will frequently use (the other one you shouldn’t even look at 🤭)
An example of mapping with Controller would be the following,
public class ProductsController : ControllerBase
{
[HttpGet("api/products")]
public IActionResult GetProducts()
{
var products = new List<string> { "Product 1", "Product 2", "Product 3" };
return Ok(products);
}
[HttpPost("api/products")]
public IActionResult CreateProduct([FromBody] string productName)
{
// Logic to create a product
return CreatedAtAction(nameof(GetProducts), new { id = 1 }, productName);
}
}
In this example,
- The action
GetProducts
responds to a GET request at the routeapi/products
- The action
CreateProduct
responds to a POST request at the same route. - The parameter
productName
is obtained from the request body thanks to the[FromBody]
attribute.