Model Binding Using FromRoute in ASP.NET Core Web API

Model Binding Using FromRoute in ASP.NET Core Web API

In this article, I will discuss Model Binding Using FromRoute in ASP.NET Core Web API Application with Examples. Please read our previous article discussing Model Binding Using FromQuery in ASP.NET Core Web API with Examples.

FromRoute in ASP.NET Core Web API

Model Binding in ASP.NET Core Web API is a mechanism that enables the application to take client request data (such as route data, query string parameters, request body contents, etc.) and convert it into objects that the controller actions can work with. FromRoute is one of the model binding attributes provided by ASP.NET Core that tells the framework to retrieve the value of a parameter from the route data.

In ASP.NET Core Web API, the FromRoute attribute binds parameter values directly from the route data. It specifies that a parameter should be bound using the route values from the current request. This is useful when you want to obtain values from the URL path of the request rather than from the query string, form data, or request body.

The FromRoute attribute is applied to action method parameters in a controller to indicate that the value for that parameter should be retrieved from the route data. The routing system will try to match the route data key with the name of the parameter, or you can explicitly specify the route data key by providing a name to the FromRoute attribute.

Example to Understand FromRoute Attribute in ASP.NET Core Web API:

Let us see an Example to Understand the FromRoute Attribute in ASP.NET Core Web API. We are going to use the following Product model. So, create a class file named Product.cs and then copy and paste the following code:

namespace ModelBinding.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Quantity { get; set; }
        public string Categogy { get; set; }
        public int Price { get; set; }
    }
}
Basic Example

Suppose you have an API endpoint that retrieves a specific Product by ID. The ID is part of the URL path. For a better understanding, please create an API Controller with the name Products Controller and then copy and paste the following code:

using Microsoft.AspNetCore.Mvc;
using ModelBinding.Models;

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private static List<Product> Products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Categogy = "Electronics", Price = 1000, Quantity = 10 },
            new Product { Id = 2, Name = "Desktop", Categogy = "Electronics", Price = 2000, Quantity = 20 },
            new Product { Id = 3, Name = "Mobile", Categogy = "Electronics", Price = 3000, Quantity = 30 },
            new Product { Id = 4, Name = "Casual Shirts", Categogy = "Apparel", Price = 500, Quantity = 10 },
            new Product { Id = 5, Name = "Formal Shirts", Categogy = "Apparel", Price = 600, Quantity = 30 },
            new Product { Id = 6, Name = "Jackets & Coats", Categogy = "Apparel", Price = 700, Quantity = 20 },
        };

        [HttpGet("{id}")] 
        public IActionResult GetProductById([FromRoute] int id)
        {
            // Logic to retrieve the user by ID
            var product = Products.FirstOrDefault(prd => prd.Id == id);
            if (product != null)
            {
                return Ok(product);
            }
            return NotFound($"No Product Found with Product Id: {id}");
        }
    }
}

In this example, the [HttpGet(“{id}”)] attribute specifies that this action handles GET requests where the URL path includes an id value (e.g., /api/products/1). The id parameter in the GetProductById method is decorated with [FromRoute], telling ASP.NET Core to bind the value from the route data to this parameter.

When a request is made to /api/products/1, ASP.NET Core matches the request to the GetProductById action because the URL path fits the route template defined by [HttpGet(“{id}”)]. The framework extracts the “1” part of the URL and assigns it to the id parameter of the GetProduct method because the id is specified as a route parameter and is marked with [FromRoute]. Now, run the application and access the above endpoint as follows:

Example to Understand FromRoute Attribute in ASP.NET Core Web API

How to Assign a Different Name to Route Parameter in ASP.NET Core Web API

By default, the name of a route parameter matches the name specified in the route template added to the URL path. However, using a different name for a route parameter inside your action method is also possible than the one specified in the route template. This can be achieved using attribute routing along with the FromRoute attribute to specify a different name. For a better understanding, please modify the Products Controller as follows. The following code is self-explained, so please go through the comment lines.

using Microsoft.AspNetCore.Mvc;
using ModelBinding.Models;

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private static List<Product> Products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Categogy = "Electronics", Price = 1000, Quantity = 10 },
            new Product { Id = 2, Name = "Desktop", Categogy = "Electronics", Price = 2000, Quantity = 20 },
            new Product { Id = 3, Name = "Mobile", Categogy = "Electronics", Price = 3000, Quantity = 30 },
            new Product { Id = 4, Name = "Casual Shirts", Categogy = "Apparel", Price = 500, Quantity = 10 },
            new Product { Id = 5, Name = "Formal Shirts", Categogy = "Apparel", Price = 600, Quantity = 30 },
            new Product { Id = 6, Name = "Jackets & Coats", Categogy = "Apparel", Price = 700, Quantity = 20 },
        };

        // Assuming your route template specifies a parameter named "Id"
        // but you want to use "ProductId" within your action method
        [HttpGet("{Id}")] 
        public IActionResult GetProductById([FromRoute(Name = "Id")] int ProductId)
        {
            // Now, you can use "ProductId" to refer to the parameter that comes from the route.
            // Fetch the Product by the ProductId and return a response
           
            var product = Products.FirstOrDefault(prd => prd.Id == ProductId);
            if (product != null)
            {
                return Ok(product);
            }
            return NotFound($"No Product Found with Product Id: {ProductId}");
        }
    }
}
In this example:
  • The route defined in the HttpGet attribute includes a parameter named Id.
  • In the GetProductById method signature, the FromRoute attribute is used to bind the value of Id from the route to the method parameter named ProductId.
  • Inside the method, you can refer to the parameter using the name ProductId, even though the route specifies the name as Id.
FromRoute Attribute with Complex Type in ASP.NET Core Web API:

While FromRoute is mostly used with simple types like int, string, etc., you can also use it with complex types, assuming the route contains enough information to fill the properties of the complex type. Let us understand this with an example. First, create a class file named ProductRoute.cs and then copy and paste the following code:

namespace ModelBinding.Models
{
    public class ProductRoute
    {
        public string Name { get; set; }
        public string Category { get; set; }
    }
}
Modifying the Products Controller:

Next, modify the Products Controller as follows. Here, we have marked the ProductRoute parameter with the FromRoute Attribute, meaning this parameter’s properties will map with the Route Data parameter.

using Microsoft.AspNetCore.Mvc;
using ModelBinding.Models;

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private static List<Product> Products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Categogy = "Electronics", Price = 1000, Quantity = 10 },
            new Product { Id = 2, Name = "Desktop", Categogy = "Electronics", Price = 2000, Quantity = 20 },
            new Product { Id = 3, Name = "Mobile", Categogy = "Electronics", Price = 3000, Quantity = 30 },
            new Product { Id = 4, Name = "Casual Shirts", Categogy = "Apparel", Price = 500, Quantity = 10 },
            new Product { Id = 5, Name = "Casual Pants", Categogy = "Apparel", Price = 600, Quantity = 30 },
            new Product { Id = 6, Name = "Jackets & Coats", Categogy = "Apparel", Price = 700, Quantity = 20 },
        };

        [HttpGet("{Name}/{Category}")]
        public IActionResult GetProductById([FromRoute] ProductRoute productRoute)
        {
            if(productRoute != null)
            {
                var FilteredProducts = Products.Where(prd => prd.Name.ToLower().StartsWith(productRoute.Name) &&
                prd.Categogy.ToLower() == productRoute?.Category.ToLower()).ToList();

                return Ok(FilteredProducts);
            }
            
            return NotFound($"No Product Found");
        }
    }
}

With the above changes in place, run the application and access the above endpoint as follows, and you should get the output as expected.

FromRoute Attribute with Complex Type in ASP.NET Core Web API

How Does FromRoute Work in ASP.NET Core Web API?

When you apply the FromRoute attribute to an action method parameter, you’re telling ASP.NET Core to use the route data to populate that parameter. The route data consists of the values for the placeholders defined in the route template. Here is how FromRoute model binding works:

  • Route Matching: When a request is received, ASP.NET Core matches the request URL to one of the configured routes. If a match is found, the framework extracts the values for any route parameters defined in the route template.
  • Model Binding: For action method parameters decorated with the FromRoute attribute, the model binder looks in the route data for a value with a key that matches the name of the parameter. If a matching key is found, the model binder attempts to convert the value to the type of the parameter.
  • Parameter Population: If the conversion is successful, the action method parameter is populated with the converted value. If no matching key is found in the route data or the conversion fails, the action might not execute, depending on the configuration and whether the parameter is optional.
FromRoute vs FromQuery in ASP.NET Core Web API

In ASP.NET Core Web API, FromRoute and FromQuery are different attribute bindings that specify how data should be bound to action method parameters. Both serve the purpose of data extraction from the request, but they operate on different parts of the HTTP request. Understanding the distinction between the two is crucial for correctly designing API endpoints and ensuring that data is accurately received and processed by your application.

FromRoute
  • Usage: The FromRoute attribute is used to bind parameter values directly from the route of the HTTP request. This is typically used for RESTful URLs where key pieces of data are embedded within the route itself.
  • Example: Consider an API endpoint designed to fetch a specific user by ID. The route might be defined as /api/users/{id}, where {id} is a placeholder for the user ID. In this case, FromRoute would be used to bind the value of {id} to the action method parameter.
  • Benefits: It allows for clean and readable URLs and is particularly useful for operations that relate to a specific resource or entity.
  • Limitations: Since the data is part of the URL, it’s not well-suited for passing complex data or sensitive information.
FromQuery
  • Usage: The FromQuery attribute binds parameter values from the query string of the HTTP request. This is useful for operations that require additional, optional, or complex filtering parameters that don’t naturally fit within the route path.
  • Example: For a search endpoint that allows filtering of results based on various criteria, the URL might look like /api/products?category=electronics&price=100. Here, FromQuery would be used to bind the category and price values to the corresponding parameters in the action method.
  • Benefits: It supports more flexible and dynamic data retrieval operations, allowing for complex queries with multiple optional parameters.
  • Limitations: Query strings can become unwieldy with too many parameters, and there are limits to URL length that might restrict the amount of data that can be passed.
Choosing Between FromRoute and FromQuery
  • RESTful Design: For endpoints that operate on a specific resource or entity, FromRoute is often the preferred choice, as it aligns with RESTful URL conventions.
  • Complex Filtering or Operations: When the operation requires complex inputs or when you’re dealing with optional or numerous parameters, FromQuery is more suitable.
  • Security Considerations: Sensitive information should generally not be passed in URLs, whether in routes or query strings, due to the risk of exposure in server logs or browser histories.

In the next article, I will discuss Model Binding Using FromHeader in ASP.NET Core Web API with Examples. In this article, I try to explain Model Binding Using FromRoute in ASP.NET Core Web API with Examples, and I hope you enjoy this article “Model Binding Using FromRoute in ASP.NET Core Web API”.

Leave a Reply

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