Model Binding Using FromBody in ASP.NET Core Web API

Model Binding Using FromBody in ASP.NET Core Web API

In this article, I will discuss How to Implement Model Binding Using FromBody in ASP.NET Core Web API Application with Examples. Please read our previous article discussing Model Binding Using FromHeader in ASP.NET Core Web API with Examples.

FromBody Attribute in ASP.NET Core Web API

Model binding in ASP.NET Core Web API is a process that maps client request data (like JSON or XML) to action method parameters. The FromBody Attribute in ASP.NET Core Web API is used to indicate that a parameter should be bound from the body of the incoming HTTP request.

This is commonly used in API methods to allow complex data types, such as JSON or XML, to be read from the request body and automatically deserialized into the method’s parameters. The ASP.NET Core model binding system then takes care of the deserialization process, converting the incoming request body into a .NET object.

Model Binding Example using FromBody

Let’s start with a basic example where we have a simple model class and an action method in a controller that uses [FromBody].

Creating Model:

First, create a class file named Product.cs, and then copy and paste the following code. This is the model class that we will use as a parameter in our action method.

namespace ModelBinding.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Quantity { get; set; }
        public int Price { get; set; }
    }
}
Creating Controller:

Next, create an API Controller named Products Controller and copy and paste the following code.

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

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        [HttpPost]
        public IActionResult CreateProduct([FromBody] Product product)
        {
            // Add the product to the database or in-memory store
            // For demonstration, let's return the product back
            return Ok(product);
        }
    }
}

In this example, when you send a POST request with a JSON body representing a Product, the ASP.NET Core model binding system will automatically populate the product parameter with the data from the request body. To test the above API, please use the following details:

Method: POST

URL: api/products

Request Body:

{
  "id": 100,
  "name": "Laptop",
  "quantity": 10,
  "price": 2500
}

You can test using Postman, as shown in the below image. Here, you need to change the API endpoint port number where your application is running.

How to Implement Model Binding Using FromBody in ASP.NET Core Web API Application with Examples

Handling Collection or Arrays using FromBody in ASP.NET Core Web API

Model binding can also handle arrays or collections. This is useful when you want to send a list of items in a single request. For a better understanding, please modify the Products Controller as follows:

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

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        [HttpPost]
        public IActionResult CreateProduct([FromBody] List<Product> products)
        {
            // Handle multiple products
            // For demonstration, let's return the products back
            return Ok(products);
        }
    }
}

In this example, you can POST an array of products in JSON format, and it will be bound to the products parameter as a collection of Product objects. To test the above API, please use the following details:

Method: POST

URL: api/products

Request Body:

[
    {
        "id": 100,
        "name": "Laptop",
        "quantity": 10,
        "price": 2500
    },
    {
        "id": 101,
        "name": "Desktop",
        "quantity": 15,
        "price": 2900
    }
]
Customizing Model Binding with Attributes

Sometimes, you might need to accept data in a format that doesn’t directly map to your model. In such cases, custom model binders can be used, but for common scenarios, attributes like [FromBody] suffice.

Model

Assume a more complex model that includes nested objects or collections. So, modify the Products.cs class file as follows:

namespace ModelBinding.Models
{
    public class Order
    {
        public int Id { get; set; }
        public List<Product> Products { get; set; }
    }

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

Next, modify the Products Controller as follows:

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

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        [HttpPost("Order")]
        public IActionResult CreateOrder([FromBody] Order order)
        {
            // Process the order
            return Ok(order);
        }
    }
}

The above example allows for a complex JSON object representing an order with an array of products to be posted and bound to the order parameter. To test the above API, please use the following details:

Method: POST

URL: api/Products/Order

Request Body:

{
    "id": 12345,
    "products": [
        {
            "id": 1,
            "name": "Laptop",
            "quantity": 1,
            "price": 2500
        },
        {
            "id": 2,
            "name": "Desktop",
            "quantity": 2,
            "price": 5000
        }
    ]
}
How Does FromBody Work in ASP.NET Core Web API?

Here is how [FromBody] works in ASP.NET Core Web API:

  • HTTP Request Identification: When a client sends a request to an ASP.NET Core Web API, the framework identifies the HTTP method and the URL. Based on the routing configuration, it determines which controller and action method should handle the request.
  • Model Binding Process: ASP.NET Core employs a model binding process to map data from HTTP requests to action method parameters. The [FromBody] attribute explicitly tells the model binder to look for data in the request’s body.
  • Content Negotiation and Deserialization: ASP.NET Core performs content negotiation using the Content-Type header of the incoming request. It selects an appropriate formatter based on the media type (e.g., application/json, application/xml). The selected formatter then deserializes the request body into the specified parameter type. This process is facilitated by input formatters configured in the API’s startup.
  • Validation: After the deserialization process, ASP.NET Core automatically performs model validation if the model implements data annotation validation attributes. If the model doesn’t pass validation, the framework can automatically send a 400 Bad Request response to the client, depending on the API’s configuration.
  • Action Method Execution: Once the parameter is successfully bound and validated, the action method executes. The deserialized and validated parameter is available for use within the method to perform business logic or data operations.
  • Response Generation: After the action method executes, the framework serializes the response into the appropriate format (again, based on content negotiation) and sends it back to the client.
Customizing Serialization and Deserialization in ASP.NET Core Web API

You can customize the deserialization process by configuring the options for the input formatters in the Program.cs class file. By default, ASP.NET Core Framework uses CamelCase naming conventions. Meaning, the first letter of the identifier is lowercase, and the first letter of each subsequent concatenated word is uppercase. If you want to ignore this naming convention, then you need to configure the same serialization settings using AddJsonOptions as follows:

builder.Services.AddControllers()
.AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

With the above changes in place, now run the application and it should work with the original property names. You can test the same as follows:

Method: POST

URL: api/Products/Order

Request Body:

{
    "Id": 12345,
    "Products": [
        {
            "Id": 1,
            "Name": "Laptop",
            "Quantity": 1,
            "Price": 2500
        },
        {
            "Id": 2,
            "Name": "Desktop",
            "Quantity": 2,
            "Price": 5000
        }
    ]
}
Response Body:

How to Implement Model Binding Using FromBody in ASP.NET Core Web API Application with Examples

What are CamelCase and PascalCase?

In Programming, CamelCase and PascalCase are two conventions used for the naming of identifiers such as variables, classes, methods, and other entities in code. These conventions indicate how multi-word identifiers are joined together. Despite their similarities, they differ primarily in the capitalization of the first letter.

CamelCase
  • Definition: In CamelCase, the first letter of the identifier is lowercase, and the first letter of each subsequent concatenated word is uppercase. It is also known as lowerCamelCase.
  • Usage: Commonly used for naming variables, methods, or functions in many programming languages.
  • Example: myVariableName, calculateTotalWidth, readUserData
PascalCase
  • Definition: In PascalCase, the first letter of each concatenated word is uppercase, including the first word. This makes all the word boundaries distinct with capital letters. It is sometimes referred to as UpperCamelCase.
  • Usage: Often used for naming classes, interfaces, namespaces, and other constructs that define types or significant structures in code.
  • Example: MyVariableName, CalculateTotalWidth, ReadUserData
Why Are Multiple FromBody Not Allowed in ASP.NET Core Web API?

In ASP.NET Core Web API, the restriction against using multiple [FromBody] attributes in a single action method is primarily due to the nature of HTTP requests and the way the request body is processed. Here are the key reasons for this limitation:

  • HTTP Request Body Can Only Be Read Once: The HTTP request body is a forward-only stream that can be read only once. Once the stream has been read and parsed (deserialized into an object), it cannot be reset or re-read by another parameter. This is a fundamental limitation of how HTTP streams are handled, not just in ASP.NET Core but in web frameworks generally.
  • Content Negotiation and Serialization: ASP.NET Core uses content negotiation and configured input formatters to deserialize the request body into a .NET object. This process is based on the Content-Type header of the request, which specifies the format of the request body (e.g., application/json, application/xml). Since the deserialization process is tied to the content type and the entire body is consumed to deserialize into one object, attempting to bind multiple parameters [FromBody] would imply multiple content types or multiple reads of the body, which is not feasible.
When to Use FromBody in ASP.NET Core Web API?

It is commonly used in scenarios where you need to accept complex data types like objects or arrays passed in the request body, often JSON or XML. Here are specific circumstances and guidelines for using [FromBody]:

  • Accepting Complex Types: When your endpoint needs to accept a complex object, you should use [FromBody]. Complex data types cannot be easily passed from the query string or URL parameters. For example, if you’re creating a new user and need to pass an object containing multiple properties (e.g., name, email, password), [FromBody] is appropriate.
  • Content-Type Requirement: The request must include a Content-Type header, usually application/json or application/xml, indicating the format of the data in the request body. The ASP.NET Core model binding system uses this header to deserialize the data into the C# object correctly.
  • POST, PUT, PATCH Methods: [FromBody] is typically used with HTTP methods intended to send data in the request body, such as POST, PUT, and PATCH. These methods are designed to create or update resources on the server and can handle complex data payloads.
  • Not Required for Simple Types: For simple types such as int, string, or DateTime that can be easily passed in the query string or as URL parameters, [FromBody] is not typically used. ASP.NET Core can bind these types from other sources like the query string ([FromQuery]), route data ([FromRoute]), or headers ([FromHeader]).

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

Leave a Reply

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