Token Replacement in ASP.NET Core Web API Routing

Token Replacement in ASP.NET Core Web API Routing

In this article, I will discuss Token Replacement in ASP.NET Core Web API Routing with Examples. Please read our previous article, which discusses How to Set Up Multiple URLs for a Single Resource in the ASP.NET Core Web API Application. We will also work with the same application we created in our Routing in ASP.NET Core Web API article. 

What are Tokens in ASP.NET Core Attribute Routing?

In ASP.NET Core, attribute routing is a feature that allows you to define routes directly on your controllers and actions using attributes. Tokens in attribute routing are placeholders that allow you to capture values from the request URI and use them as parameters in your route templates.

Tokens are enclosed in curly braces {} and can be placed within the route template to capture specific parts of the URI. These captured values can then be used as parameters in your action methods. Here are some common tokens used in attribute routing:

  • {controller}: Represents the controller name.
  • {action}: Represents the action method name.
  • {id}: Represents a parameter named “id” in the route.
Example Without Using Token Replacement in ASP.NET Core Web API

Before understanding the need and use of token replacement, let us first understand an example without using token replacement. Suppose we have two resources in our Employee Controller, and we want to access the two resources using the controller/action method name. Then, we can do the same without token replacement, as shown in the code below.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]   
    public class EmployeeController : ControllerBase
    {
        [Route("Employee/GetAllEmployees")]
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        [Route("Employee/GetAllDepartment")]
        [HttpGet]
        public string GetAllDepartment()
        {
            return "Response from GetAllDepartment Method";
        }
    }
}

Now run the application, and you can access both the resource using the controller and action method name, as shown in the below image.

Example Using Token Replacement in ASP.NET Core Web API Application

Let us understand how the token replacement works in the ASP.NET Core Web API Application with an example. Please modify the Employee Controller class that we have been working on so far, as shown below. As you can see, here we are applying the token [controller] on the EmployeeController. At the same time, we are also applying the token [action] on all the action methods of the Employee Controller.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class EmployeeController : ControllerBase
    {
        [Route("[action]")]
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        [Route("[action]")]
        [HttpGet]
        public string GetAllDepartment()
        {
            return "Response from GetAllDepartment Method";
        }
    }
}

Now, with the above changes in place, you can access the GetAllEmployees method with the URL: /Employee/GetAllEmployees and the GetAllDepartment method with the URL: /Employee/GetAllDepartment, as shown in the image below. This is because at the run time, the token [controller] will be replaced by Employee, and the token [action] will be replaced by the respective action method of the controller.

Do we need to write the action token on each action method?

Not Really. If you want all your action methods of the controller to apply an action token, then instead of including the [action] token on each and every action method, you can apply it only once on the controller.

Let us understand this with an example. Please modify the Employee Controller class as shown in the below code. As you can see in the below code, we have removed the [Route(“[action]”)] attribute from the action method and modified the Route attribute as [Route(“[controller]/[action]”)], which is applied at the controller level.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]
    [Route("[controller]/[action]")]
    public class EmployeeController : ControllerBase
    {
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        [HttpGet]
        public string GetAllDepartment()
        {
            return "Response from GetAllDepartment Method";
        }
    }
}

Now, with the above changes in place, you can also access the GetAllEmployees method with the URL: /Employee/GetAllEmployees and the GetAllDepartment method with the URL: /Employee/GetAllDepartment, as shown in the below image.

blank

Token Replacement with Dynamic Values:

Now, let us see an example of token replacement with dynamic values. Our requirement is to fetch employee information by employee ID. Here, the employee ID is the dynamic value, and this value will come as part of the URL. Let us see how we can achieve this. Here, we need to decorate the Route attribute at the action method as shown below.

[Route("{Id}")]
[HttpGet]
public string GetEmployeeById(int Id)
{
    return $"Response from GetEmployeeById Method, Id : {Id}";
} 

So, at the run time, the [Route(“[controller]/[action]”)] will evaluate first, and then [Route(“{Id}”)] will be added to the route which will form the URL as Employee/GetEmployeeById/10. So, modify the Employee Controller class as shown below.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]
    [Route("[controller]/[action]")]
    public class EmployeeController : ControllerBase
    {
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        [HttpGet]
        public string GetAllDepartment()
        {
            return "Response from GetAllDepartment Method";
        }

        [Route("{Id}")]
        [HttpGet]
        public string GetEmployeeById(int Id)
        {
            return $"Response from GetEmployeeById Method, Id : {Id}";
        }
    }
}

Now save the changes, run the application, and access the GetEmployeeById, as shown in the below image, and you should see the response as expected.

blank

Example: controller and action token applied to the action method

In the example below, we are applying the Route Attribute only at the action method level, and it will also work as expected.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]   
    public class EmployeeController : ControllerBase
    {
        [Route("[controller]/[action]")]
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        [Route("[controller]/[action]")]
        [HttpGet]
        public string GetAllDepartment()
        {
            return "Response from GetAllDepartment Method";
        }

        [Route("[controller]/[action]/{Id}")]
        [HttpGet]
        public string GetEmployeeById(int Id)
        {
            return $"Response from GetEmployeeById Method, Id : {Id}";
        }
    }
}
Example to Understand how tokens are used with HTTP methods in Attribute Routing:

Instead of applying the tokens into Route Attribute, we can also apply the same with the HTTP Methods. For a better understanding, please have a look at the following example.

using Microsoft.AspNetCore.Mvc;
namespace RoutingInASPNETCoreWebAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class EmployeeController : ControllerBase
    {
        //GET: /api/Employee
        [HttpGet]
        public string GetAllEmployees()
        {
            return "Response from GetAllEmployees Method";
        }

        //GET: /api/Employee/100
        [HttpGet("{id}")]
        public string GetEmployeeById(int id)
        {
            return $"Response from GetEmployeeById Method, Id : {id}";
        }

        //GET: /api/Employee/department/IT
        [HttpGet("department/{department}")]
        public string GetEmployeeByDepartment(string department)
        {
            return $"Response from GetEmployeeByDepartment Method, Department :{department}";
        }
    }
} 

In the example above:

  • The [HttpGet] attribute on the GetAllEmployees action method specifies a route template of “api/[controller]”, where [controller] is a token that will be replaced with the controller name (Products in this case).
  • The [HttpGet(“{id}”)] attribute on the GetEmployeeById action method specifies a route template with the {id} token, indicating that the action expects an id parameter from the route.
  • The [HttpGet(“department/{department}”)] attribute on the GetEmployeeByDepartment action method uses the {department} token to capture a category parameter from the route.

When a request is made, ASP.NET Core will match the incoming URI with the defined route templates and extract token values. These values are then passed as parameters to the corresponding action method.

When should you use Token Replacement in ASP.NET Core Web API Routing?

In ASP.NET Core Web API, token replacement in routing is a technique used to define routes with variable placeholders that are replaced by actual values at runtime. This approach is fundamental for creating flexible and dynamic APIs that can adapt to various resource identifiers or action requests. The usage of token replacement in routing is critical for several reasons and scenarios:

Resource Identification: When you need to access specific resources, such as a user or a product, by an identifier (e.g., ID, username).
Example: /api/users/{userId} or /api/products/{productId} where {userId} and {productId} are tokens replaced by actual values during a request.

Hierarchical Resources: For accessing resources that are nested within other resources, reflecting a hierarchical relationship.
Example: /api/authors/{authorId}/books/{bookId} to access a specific book by an author, where both {authorId} and {bookId} are tokens.

Action-Specific Routes: When different actions on the same resource type require distinct routes.
Example: /api/orders/{orderId}/approve and /api/orders/{orderId}/reject where different endpoints trigger approval or rejection actions for an order.

Dynamic Content Negotiation: To serve different resource formats based on the request (though often handled by ASP.NET Core’s built-in content negotiation features).
Example: /api/reports/{reportId}/{format} where {format} could be replaced with pdf or excel.

Versioning: For API versioning, different versions of the API are accessed through the URL.
Example: /api/v{version}/products/{productId} allowing the API to route requests to different versions of a controller based on the {version} token.

Guidelines for Using Token Replacement
  • Clarity and Simplicity: Keep routes intuitive and easy to understand. Overly complex routes can make the API difficult to use and maintain.
  • Consistency: To avoid confusion, apply a consistent naming convention for tokens across your API.
  • Security: Validate token values to prevent injection attacks or unauthorized resource access.
  • Performance: While dynamic routes are powerful, ensure that the routing logic and token validation do not introduce significant overhead.

Using the common part of the Route at the Controller level is always recommended. In fact, in the next article, I will discuss How to set the common or base route at the controller level in ASP.NET Core Web API Routing with Examples. In this article, I try to explain token replacement in ASP.NET Core Web API Attribute Routing with examples. I hope you enjoy this Token Replacement in the ASP.NET Core Web API Attribute Routing article.

Leave a Reply

Your email address will not be published. Required fields are marked *