Exclude Properties from Model Binding in ASP.NET Core Web API

How to Exclude Properties from Model Binding in ASP.NET Core Web API

In this article, I will discuss How to Exclude Properties from Model Binding in ASP.NET Core Web API Applications with Examples. Please read our previous article discussing How to Implement Content Negotiation in ASP.NET Core Web API Application with Examples.

Exclude Properties from Model Binding in ASP.NET Core Web API:

In ASP.NET Core Web API, model binding is the process that automatically maps incoming request data such as route data, query strings, or JSON or XML request body to action method parameters or model properties. This mechanism facilitates the transfer of data between the client and server. However, there are some scenarios where we might need to include or exclude specific properties from this binding process based on certain conditions. Controlling which properties are bound is essential for:

  • Security: Preventing over-posting attacks where the client could set fields they shouldn’t be able to control (like setting an internal IsAdmin property to true).
  • Clarity and Maintenance: Simplify models by focusing only on the relevant fields for a given operation.
  • Performance: Optimizing the data being transferred and processed.
  • API Design: Control what is returned in API responses, keeping some fields private or internal to the application logic. Maintain a Clean Contract between the server and the client.
Why Exclude Properties from Model Binding in ASP.NET Core:

Let’s understand why we need to Exclude Properties from Model Binding in an ASP.NET Core Web API Application with an Example. So, create a new ASP.NET Core Web API Project named ModelBinding, and then, at the project root directory, create a folder named Models.

Defining the Employee Model

First, create an Employee model that represents the employee data structure. So, create a class file named Employee.cs within the Models folder and copy and paste the following code. In this model, ID and Salary are considered sensitive and should not be exposed or modified directly by clients.

namespace ModelBinding.Models
{
    public class Employee
    {
        public int Id { get; set; }  // Sensitive property
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        public int Salary { get; set; }  // Sensitive property
        public string Department { get; set; }
    }
}
Creating the Employee Controller:

Next, create the EmployeeController to handle HTTP requests related to employees. So, create an Empty API Controller named EmployeeController within the Controllers folder and copy and paste the following code. The GetEmployees action method is used to return all the Employees, and the AddEmployee method is used to add a new Employee.

using Microsoft.AspNetCore.Mvc;
using ModelBinding.Models;
namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private static readonly List<Employee> listEmployees = new List<Employee>()
        {
            new Employee(){ Id = 1, Name = "Anurag", Age = 28, Salary = 1000, Gender = "Male", Department = "IT" },
            new Employee(){ Id = 2, Name = "Pranaya", Age = 28, Salary = 2000, Gender = "Male", Department = "IT" },
        };

        // Returns the list of all employees.
        // GET api/Employee
        [HttpGet]
        public ActionResult<List<Employee>> GetEmployees()
        {
            return Ok(listEmployees);
        }

        // Adds a new employee to the list. 
        // POST api/Employee
        [HttpPost]
        public ActionResult<Employee> AddEmployee(Employee employee)
        {
            if (employee != null)
            {
                // Manually setting the Id and Salary to prevent client manipulation
                employee.Id = listEmployees.Count + 1;
                employee.Salary = 3000;
                listEmployees.Add(employee);
                return Ok(employee);
            }

            return BadRequest();
        }
    }
}

If you run the application, it will work as expected.

GET Request:

Accessing api/employee with an HTTP GET request returns all employees with all properties, including Id and Salary. You will get all the employees as shown in the below image:

Include and Exclude Properties from Model Binding in ASP.NET Core Web API

POST Request:

Sending an HTTP POST request with employee data adds a new employee with the data in the request body, as shown in the below image, and it should work as expected. However, if you include ID and salary in the request body, the controller will override them. The ID and Salary are set on the server side to prevent clients from manipulating these sensitive fields.

How to Exclude Properties from Model Binding in ASP.NET Core Web API

How to Exclude Properties from Model Binding in ASP.NET Core Web API:

Now, our requirement is that we don’t want to expose the ID and Salary of the Employee. We don’t want to return the Employee ID and Salary in the GET request. At the same time, we don’t want to accept the ID and Salary in the Post request. So, we want to exclude the ID and Salary from the Model Binding. This is essential for security and data integrity, ensuring clients cannot manipulate sensitive fields.

So, to enhance security and control over which properties clients can send or receive, we can exclude specific properties from the model binding process. There are two primary methods to exclude properties from model binding:

  • Using the JsonIgnore Attribute
  • Using a Custom Data Transfer Object (DTO)
Excluding Properties with [JsonIgnore] in ASP.NET Core Web API

The [JsonIgnore] attribute prevents specific properties from being serialized to JSON when sending responses and deserialized from JSON when receiving requests. This is part of the System.Text.Json.Serialization namespace. That means the [JsonIgnore] attribute tells the ASP.NET Core JSON serializer to skip (ignore) a property during both serialization (when sending responses) and deserialization (when receiving requests).

For the properties you want to exclude from Model binding, you need to decorate those properties with the JsonIgnore Attribute. In our example, we want to exclude ID and Salary from Model Binding, so we must decorate these two properties using JsonIgnore Attribute. So, please modify the Employee class as follows:

using System.Text.Json.Serialization;
namespace ModelBinding.Models
{
    public class Employee
    {
        [JsonIgnore]
        public int Id { get; set; }  // Sensitive property
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        [JsonIgnore]
        public int Salary { get; set; }  // Sensitive property
        public string Department { get; set; }
    }
}
Code Explanation:

With [JsonIgnore] on Id and Salary, those properties will not appear in the JSON response and will not be deserialized from the JSON in the request body.

  • GET Requests: The ID and Salary properties will not appear in the JSON response.
  • POST Requests: Any ID and Salary values sent in the request body will be ignored during model binding, preventing clients from setting these values.
GET Request:

With the above changes in place, run the application and access the api/employee endpoint using an HTTP GET Request; the response JSON will exclude ID and Salary, as shown in the below image:

Excluding Properties with [JsonIgnore] in ASP.NET Core Web API

POST Request:

Even if the client sends the ID and Salary in the request body, these values will be ignored, and the server will set them manually. Now, please make an HTTP POST request with ID and Salary column values, and then Model Binding will ignore those values. To prove this, run the application in debug mode and place the debugger point on the CreateEmployee action method. Let us make an HTTP POST request from Postman with the ID and Salary values as follows:

Excluding Properties with [JsonIgnore] in ASP.NET Core Web API

Now, if you verify the employee object values, then you will see it is taking the default values for Integer as 0, as shown in the below image.

How to Exclude Properties with [JsonIgnore] in ASP.NET Core Web API

When to use JsonIgnore Attribute:
  • If you have a simple requirement to permanently hide or ignore a property across all operations and all endpoints (e.g., a property that should never be displayed or updated by external clients).
  • It is good for smaller projects or straightforward cases where your domain model and API contract align well, and you do not expect to expose specific fields at all.
Excluding Properties with Data Transfer Objects (DTOs)

Using DTOs involves creating separate classes that define exactly which properties the API should expose or accept. This approach provides a clear separation between the internal data models and the data exposed to clients. This approach is beneficial when we have complex models or want to decouple our API contracts from our data models.

So, let us create a new class file named EmployeeDTO.cs and copy and paste the following code. As you can see, this class only has those properties in which we want to participate in model binding. Here, we are not including the ID and Salary properties.

namespace ModelBinding.Models
{
    public class EmployeeDTO
    {
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        public string Department { get; set; }
    }
}
Modifying Employee Model:

Now, you can modify the Employee Model as follows. Here, we are removing the JsonIgnore Attribute:

namespace ModelBinding.Models
{
    public class Employee
    {
        public int Id { get; set; }  // Sensitive property
        public string Name { get; set; }
        public string Gender { get; set; }
        public int Age { get; set; }
        public int Salary { get; set; }  // Sensitive property
        public string Department { get; set; }
    }
}
Modifying the Employee Controller:

In our controller methods, we need to use EmployeeDTO instead of Employee and manually (or using a tool like AutoMapper) map back and forth to the domain entity as needed. So, modify the Employee Controller as follows:

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

namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private static readonly List<Employee> listEmployees = new List<Employee>()
        {
            new Employee(){ Id = 1, Name = "Anurag", Age = 28, Salary = 1000, Gender = "Male", Department = "IT" },
            new Employee(){ Id = 2, Name = "Pranaya", Age = 28, Salary = 2000, Gender = "Male", Department = "IT" },
        };

        [HttpGet]
        public ActionResult<List<EmployeeDTO>> GetEmployees()
        {
            var employeesDTO = listEmployees.Select(emp => new EmployeeDTO
            {
                Name = emp.Name,
                Age = emp.Age,
                Gender = emp.Gender,
                Department = emp.Department
            }).ToList();

            return Ok(employeesDTO);
        }

        [HttpPost]
        public ActionResult<EmployeeDTO> AddEmployee(EmployeeDTO employeeDTO)
        {
            if (employeeDTO != null)
            {
                var newEmployee = new Employee
                {
                    Id = listEmployees.Count + 1,    // Set server-side
                    Salary = 3000,                   // Set server-side
                    Name = employeeDTO.Name,
                    Age = employeeDTO.Age,
                    Gender = employeeDTO.Gender,
                    Department = employeeDTO.Department
                };

                listEmployees.Add(newEmployee);
                return Ok(employeeDTO);
            }
            return BadRequest();
        }
    }
}

With these changes in place, run the application, and it should work as expected. Instead of manually mapping the data between the Employee and EmployeeDTO objects, you can use frameworks like Automapper, which we will discuss in our upcoming sessions.

When to use Data Transfer Object:
  • If you want complete control over how data is shaped or transformed between client and server.
  • If your domain model contains sensitive or irrelevant fields that you do not want to expose via the API at all.
  • If you anticipate that different clients or different endpoints might have different data requirements.
  • If you want to avoid tightly coupling your EF Core entities (or domain models) to the API contract.
DTOs vs. [JsonIgnore] in ASP.NET Core Web API:

Performance: From a performance standpoint, [JsonIgnore] is lightweight since it relies on built-in serialization behavior. DTOs may introduce a slight overhead if you manually map fields or use mapping libraries (like AutoMapper). However, the difference is generally negligible unless you deal with a high throughput scenario.

Maintainability:
  • DTOs: Better for long-term maintenance as they clearly define the shape of the data for a given operation. They help enforce clean separation of concerns and can prevent accidental exposure of internal fields.
  • [JsonIgnore]: Useful for quick adjustments, but can become cumbersome if you have many properties to manage or if the model’s usage varies widely across multiple endpoints.
Real-World Scenarios:
  • Use [JsonIgnore] when you have a small number of fields to exclude and the logic is straightforward.
  • Use DTOs when the same domain model is used in multiple contexts (e.g., read vs. write operations, different client versions), and you want a clean, consistent contract for each use case.

Controlling which properties are included or excluded during model binding is essential for building secure and efficient ASP.NET Core Web APIs. Depending on your application’s complexity and requirements, you can choose between using the [JsonIgnore] attribute for quick exclusions or implementing Data Transfer Objects (DTOs) for a more structured and flexible approach. Both methods have their merits, and often, a combination of strategies yields the best results.

In the next article, I will discuss How to Implement Server Side Validation using Data Annotations in ASP.NET Core Web API with Examples. In this article, I try to explain How to Include and Exclude Properties from Model Binding in ASP.NET Core Web API with Examples, and I hope you enjoy this article, “How to Exclude Properties from Model Binding in ASP.NET Core Web API.”

Leave a Reply

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