How to Apply Binding Attributes to Model Properties in ASP.NET Core Web API

How to Apply Binding Attributes to Model Properties in ASP.NET Core Web API

In this article, I will discuss How to Apply Model Binding Attributes to Model Properties in ASP.NET Core Web API Application with Examples, i.e., how to apply FromRoute, FromQuery, and FromHeader Attribute to Model Properties. Please read our previous article discussing Custom Model Binding in ASP.NET Core Web API with Examples.

Applying Model Binding Attributes to Model Properties in ASP.NET Core Web API:

In ASP.NET Core Web API, Model Binding enables the framework to extract data from HTTP requests and map it to action method parameters or model properties. Binding attributes like [FromRoute], [FromQuery], [FromHeader], and [FromBody] help explicitly define from where specific pieces of data should come from an incoming request. For example, we can indicate whether a parameter should be read from the route URL, the query string, HTTP headers, or the request body. 

When to Use Binding Attributes

Understanding when to apply each binding attribute is crucial for effective API design:

  • FromRoute]: This attribute is used when the data, such as IDs or other identifiers, is embedded in the URL path. For example, in a route like /api/products/{id}, the {id} segment in the URL can be bound directly to a parameter or property using [FromRoute].
  • [FromQuery]: Apply this to parameters that should be retrieved from the query string. It is ideal for optional data, such as pagination or filtering parameters in HTTP GET requests. Example: /api/products?page=2&size=10
  • [FromHeader]: Use this when extracting data from HTTP headers. It’s typically used for metadata or control information, such as API versioning, authorization tokens, localization settings, etc. Example: Authorization: Bearer <token>
  • [FromBody]: The [FromBody] attribute binds complex objects from the request body. It is especially useful for creating or updating resources through POST, PUT, or PATCH requests where the body contains JSON or XML data. For example, when sending JSON data representing a new product, [FromBody] allows automatic deserialization of that JSON into a model object.
Real-Time Use Case and Example Scenario

Imagine you are building an online library management system. You have a microservice (the Books service) responsible for adding new books to the inventory. The information required for adding a new book might come from different parts of the request:

  • Book ID: Passed as part of the URL path (i.e., route) because you want PUT /api/books/{id} to represent updating a specific book resource or GET /api/books/{id} to fetch a specific book.
  • Category: Passed in the query string for quick filtering or grouping logic (?category=Technical or ?category=Fiction).
  • User ID: Passed in a custom header (X-User-Id) to identify the user performing this action (for auditing or logging purposes).
  • Book Details: A complex object (title, author, publication year, content) passed in the request body in JSON format, which is easiest for the client to supply when creating a new book.
Why Do We Need This Scenario in a Real Application?
  • Auditing: The UserId in the header tells us who is performing the action; it is very useful for user tracking, analytics, or audit purposes.
  • Routing Clarity: The id in the path ensures a RESTful approach (each book has a unique route).
  • Flexible Filtering: The client can easily alter query parameters like categories to categorize books without modifying the resource path.
  • Complex Data: The request body can carry the entire set of book properties (title, author, year, content, etc.) in a structured JSON format, which is straightforward to parse and store in a database.

This scenario is common in real-world microservices and RESTful APIs, where we need to mix different data sources in a single endpoint call. It keeps our API design clean and predictable while allowing us to handle complex input effectively.

Example to Understand Binding Attributes in ASP.NET Core Web API Application:

Let us understand how to apply Binding Attributes to Model Properties in ASP.NET Core Web API Application with one example. We will implement this in 2 ways. They are as follows:

  1. Decorating the Action Method Parameters with Binding Attribute
  2. Creating a Complex Model with Properties Decorated with Binding Attributes.
Decorating the Action Method Parameters with Binding Attribute

Let us first see how we can implement the example by decorating the action method parameters using Binding Attribute. First, create a new ASP.NET Core Web API Project named LibraryAPI. Then, create a folder named Models in the project root directory.

Creating Book Model:

First, define a model to hold the detailed information about a book. So, create a class file named BookDetails.cs within the Models folder and copy and paste the following code:

namespace LibraryAPI.Models
{
    public class BookDetails
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public int Year { get; set; }
        public string Content { get; set; }
    }
}
Creating Books Controller:

Next, create a controller to handle book-related actions. Next, create a controller to handle book-related actions. So, create an API Empty Controller named BooksController within the Controllers folder and copy and paste the following code. As you can see, we are decorating the Id parameter with FromRoute, the Category parameter with FromQuery, the UserId parameter with FromHeader(Name = “X-User-Id”), and the Details parameter with the FromBody Attribute.

using Microsoft.AspNetCore.Mvc;
using LibraryAPI.Models;

namespace LibraryAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BooksController : ControllerBase
    {
        [HttpPost("{id}")]
        public IActionResult CreateBook(
            [FromRoute] int id,
            [FromQuery] string category,
            [FromHeader(Name = "X-User-Id")] string userId,
            [FromBody] BookDetails details)
        {
            // Your logic to store the data (e.g., in a database)
            // For demonstration, we'll just return the data in a response.
            var response = new
            {
                BookId = id,
                Category = category,
                UserId = userId,
                Title = details.Title,
                Author = details.Author,
                Year = details.Year
            };

            return Ok(response);
        }
    }
}
Test the API:

To test the above endpoint, please use the following details. Please change the Port Number where your application is running. Here, we pass 1001 as the Id value and Technical as the Category string value. We also pass the custom header X-User-Id with the value 100XYZ234PKR and the request body.

URL: https://localhost:7112/api/Books/1001?Category=Technical
Method: Post
Header: X-User-Id: 100XYZ234PKR
Request Body:

{
  "Title": "ASP.NET Core Web API",
  "Author": "Pranaya",
  "Year": 2024,
  "Content": "ASP.NET Core is Open-Source and Cross Platform Web Development Framework"
}

Please see the image below to test it using Postman. Remember to include the Request body.

How to Apply Binding Attributes to Model Properties in ASP.NET Core Web API

Applying Bind Attribute to Model Properties in ASP.NET Core Web API:

Instead of decorating controller action parameters, we can decorate model properties. This approach centralizes the binding logic in the model itself, which can be beneficial for code organization and readability, especially when multiple actions require the same shape of data.

So, create a class file named Book.cs within the Models folder and then copy and paste the following code. As you can see, we are decorating the model properties with the required Binding Attribute as per our requirement:

using Microsoft.AspNetCore.Mvc;
namespace LibraryAPI.Models
{
    public class Book
    {
        [FromRoute(Name = "id")] // Binds to the route parameter {id}
        public int Id { get; set; }

        [FromQuery] // Binds to the query string parameter 'category'
        public string Category { get; set; }

        [FromHeader(Name = "X-User-Id")] // Binds to the header 'X-User-Id'
        public string UserId { get; set; }

        [FromBody] // Binds to the request body
        public BookDetails Details { get; set; }
    }
}

Note: You can only have one [FromBody] in a request because the body can be deserialized once. If you need multiple complex objects from the body, consider combining them into a single object.

Modify the BooksController

Use the Book model as a single parameter in the action method. The framework automatically binds each property based on the attributes defined in the model. The Id property will be mapped with the route data, the Category property will be mapped with the Query String data, and the UserId property will be mapped with the custom request header “X-User-Id.” The Details complex property will be mapped from the Request body. So, please modify the BooksController as follows:

using Microsoft.AspNetCore.Mvc;
using LibraryAPI.Models;

namespace LibraryAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BooksController : ControllerBase
    {
        [HttpPost("{id}")]
        public IActionResult CreateBook(Book request)
        {
            // Logic to store the data in the database would go here.
            // For demonstration, we'll return the received data as a response.

            var response = new
            {
                BookId = request.Id,
                Category = request.Category,
                UserId = request.UserId,
                Title = request.Details.Title,
                Author = request.Details.Author,
                Year = request.Details.Year
            };

            return Ok(response);
        }
    }
}

With the above changes in place, run the application, and you should get the same output as the previous one.

Advantages of Using Binding Attributes:

Applying binding attributes to Model Properties offers several benefits:

  • Explicit Data Mapping: Each piece of data is clearly bound to its source, making it transparent where each value originates.
  • Flexible Data Sources: Within the same API method, we can mix and match data sources such as route parameters, query strings, headers, and the request body.
  • Enhanced Readability: Annotating model properties directly can make the model self-descriptive, improving code readability and maintainability.
  • Validation and Security: We can implement more precise validation and security measures by clearly defining where data comes from.

Applying model binding attributes in ASP.NET Core Web API is a powerful technique to control how data from HTTP requests is mapped to your application’s parameters and models. In real-time applications like an e-commerce platform, model binding attributes make it easy to handle complex API requests. For instance, when an API endpoint involves multiple pieces of data coming from different sources, such as route parameters, query strings, headers, and bodies, model binding attributes provide an elegant and maintainable solution for organizing and processing the incoming request.

In the next article, I will discuss Content Negotiation in ASP.NET Core Web API with Examples. In this article, I will explain how to apply model binding attributes to model properties in ASP.NET Core Web API with examples. I hope you enjoy this article.

1 thought on “How to Apply Binding Attributes to Model Properties in ASP.NET Core Web API”

Leave a Reply

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