Understanding Model Binding in ASP.NET Core with .NET 8

In this article, I will explain what model binding is in .NET Core and how it works when a user makes a request, mapping the request data to action method parameters using various model binding techniques. .NET Core offers a powerful model binding feature that automatically maps client request data to action method parameters and processes the response efficiently.

I will provide detailed demonstrations of various model binding techniques, including how to bind data from query strings, form submissions, route parameters, HTTP headers, and the request body. Each technique will be explained step by step using Swagger UI requests and corresponding action methods. Additionally, we will use debugging mode to visually illustrate the binding process, making it simple and easy to understand.

ASP.NET

What is model binding in the .NET Core?

Model binding is a powerful feature of ASP.NET Core that streamlines the process of mapping HTTP request data to action method parameters or model properties. It simplifies extracting data from multiple sources, such as query strings, form submissions, route parameters, and headers. Let’s explore how model binding operates in ASP.NET Core in more detail.

Model Binding Overview

  • Model binding is the process of mapping data from HTTP requests (e.g., query strings, form data, route data) to action method parameters or properties of model classes.
  • This process is automatic and happens before your action method is called.

Default Model Binding Process

Model binding is the process by which the framework extracts data from a request and maps it to action parameters or model properties. ASP.NET Core utilizes model binding to fill action method parameters, set model properties, and carry out validation. This data can originate from various sources, as shown below.

Model Binding From where data extracted
Query strings Data from URL query parameters
Form data Data submitted in forms (POST requests)
Route data Data extracted from the URL route
Headers Data from HTTP headers
Request body Data from the request body (e.g., JSON payload)

Let’s explore each concept with examples. First, we'll create a Product class that we'll use in our API for demonstration purposes.

Product

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Now, create ProductController with all types of binding.

 ProductController

using DotNetCoreModelBinding.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace DotNetCoreModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        /// <summary>
        /// Get product using FromQuery which takes values from QueryString
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet("byquery")]
        public IActionResult GetProduct(int id, string name)
        {
            // Create a product using query parameters
            var product = new Product { Id = id, Name = name, Price = 0 };
            return Ok(product);
        }

        /// <summary>
        /// Create Product From Form which takes values from form
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        [HttpPost("fromform")]
        public IActionResult CreateProductFromForm([FromForm] Product product)
        {
            // Process the product from form data
            return Ok(new { Message = "Product created from form data!", Product = product });
        }

        /// <summary>
        /// Create Product From Form which takes values from Route
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("byroute/{id}")]
        public IActionResult GetProductByRoute([FromRoute] int id)
        {
            // Create a product using route data
            var product = new Product { Id = id, Name = "ProductC", Price = 0 };
            return Ok(product);
        }

        /// <summary>
        /// Get Product From Form which takes values from header
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet("byheader")]
        public IActionResult GetProductByHeader([FromHeader(Name = "X-Product-Id")] int id, [FromHeader(Name = "X-Product-Name")] string name)
        {
            // Create a product using header data
            var product = new Product { Id = id, Name = name, Price = 0 };
            return Ok(product);
        }

        /// <summary>
        /// Create Product From Form which takes values from body
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        [HttpPost("bybody")]
        public IActionResult CreateProductByBody([FromBody] Product product)
        {
            // Process the product from request body data
            return Ok(new { Message = "Product created from request body!", Product = product });
        }

    }
}

After running the project, we will be directed to the Swagger homepage, which displays a list of all available endpoints. From there, we will explore each type of binding in detail.

Swagger homepage

This section illustrates several approaches to model binding in .NET Core using Swagger.

Model

Let's go through each approach individually using the Swagger UI. Enter the necessary values for the endpoints, and use the Visual Studio debugger to inspect these values in detail.

1. ByQuery

On the screen below, you can observe how the ID and name passed as query strings are mapped in the GetProduct method.

GetProduct

Extract data from the Query String

Request URL: https://localhost:7040/api/Products/byquery?id=1&name=Jignesh

URL

2. Extract data from the form

In this model binding technique, data submitted through a form is mapped to the parameters of a POST action method, where it is automatically bound to the corresponding properties or parameters in the method.

Post Action

Request URL and CURL command for form

CURL command

3. Extract data from Route

In this model binding technique, data submitted through a route is mapped to the parameters of an action method, where it is automatically bound to the corresponding properties or parameters in the method.

Route

Request URL and CURL command for route

CURL

4. Extract data from the header

In this model binding technique, data submitted through a header is mapped to the parameters of an action method, where it is automatically bound to the corresponding properties or parameters in the method.

Header

Request URL and CURL command for header

Command

5. Extract data from the body

In this model binding technique, data submitted through a body is mapped to the parameters of an action method. ASP.NET Core can automatically bind JSON or XML data in the request body to complex objects using model binding. This is particularly useful when dealing with structured data sent from a client application. In our example, the JSON data for the product was sent to the request body and was automatically mapped to the Product class object parameter.

Data

Request URL and CURL command for body

Request URL

Summary

In this article, we explored the functionality of model binding in .NET Core and gained an understanding of how it simplifies the process of mapping incoming request data to action method parameters. I provided detailed demonstrations of various model binding techniques, including how to bind data from query strings, form submissions, route parameters, HTTP headers, and the request body. Through these examples, we saw how .NET Core efficiently handles different sources of input data and automatically binds them to action method parameters, enhancing the overall development experience.