Mastering ASP.NET Core 2.1 : Instructor-led online course by Bipin Joshi in November 2018. Read more...
Live instructor-led online courses in ASP.NET Core and Design Patterns. Registration is open for November 2018 batch. More details are available here.

Automatic Model Validation and Parameter Binding using ApiController Attribute

While developing ASP.NET Core Web API you need to perform model validation manually. You also need to bind action parameters explicitly using attributes such as [FromBody]. The [ApiController] attribute introduced in ASP.NET Core 2.1 can automate both of these tasks for you. This article explains how.

Consider the following Post() action from a Web API controller - CustomerController.

[Route("api/[controller]")]
public class CustomerController : Controller
{
    [HttpPost]
    public IActionResult Post([FromBody]Customer obj)
    {
        if(ModelState.IsValid)
        {
            //insert customer
            return Ok();
        }
        else
        {
            return BadRequest();
        }
    }
}

The CustomerController contains just a single action - Post() - that is supposed to insert a new customer in the database. Notice a couple of things about this action:

  • The action checks the ModelState.IsValid manually. And depending on the outcome either returns 200 - Ok or 400 - Bad request as its response.
  • The Post() action takes one parameter - obj - that is bound with the incoming request body using [FromBody] attribute. In the absence of [FromBody] obj will be null even though the client sends data as a part of request body.

The Customer model class involved in the Web API is shown below:

public class Customer
{
    [Required]
    [StringLength(5)]
    public string ID { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }
}

Notice the use of validation attributes such as [Required] and [StringLength] to validate Customer ID and Name properties.

Wouldn't it be nice if these simple yet common tasks are taken care of by the framework itself? That's what [ApiController] attribute does.

Let's see how to use it. Have a look at the following code:

[Route("api/[controller]")]
[ApiController]
public class CustomerController : Controller
{
    [HttpPost]
    public IActionResult Post(Customer obj)
    {
       //insert customer
       return Ok();
    }
}

Notice that the CustomerController is now decorated with [ApiController] attribute. The Post() action no longer has the model validation code. Moreover, the obj parameter is not explicitly bound with the request body using [FromBody] attribute. All these aspect are automatically taken care by the [ApiController] attribute.

Since [ApiController] is introduced in ASP.NET Core 2.1 you also need to set the compatibility version in the Startup class as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services
    .AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

The SetCompatibilityVersion() method sets the compatibility to version 2.1. This line of code is required for [ApiController] to work as expected. So, make sure to add in your application startup as explained above.

Now that we have [ApiController] in place, let's test whether it works as expected. The following jQuery code makes a POST request to the CustomerController.

$(document).ready(function () {

    var options = {};
    options.url = "/api/customer";
    options.type = "POST";
    options.contentType = "application/json";

    var obj = {};
    obj.ID = "AFLKI";
    obj.Name = "Company Name 1";

    options.data = JSON.stringify(obj);
    options.dataType = "json";
    options.success = function () {
        console.log("Success!");
    };
    options.error = function (a,b,c) {
        console.log(a);
        console.log(b);
        console.log(c);
    };

    $.ajax(options);
});

The above code creates a new Customer object (with ID and Name properties) and sets the data property. The $.ajax() initiates the POST request to the Web API.

Set a breakpoint in the Post() action and run the application.

If you pass valid values for ID and Name properties, the POST request will reach the Post() action breakpoint. Moreover, the obj parameter will have correct ID and Name values even if you didn't use [FromBody] attribute.

Now, set some invalid value for ID property, say - ALFKI123 (more than 5 characters) and run the application again. This time the framework will detect that ModelState is invalid and will respond with 400 - Bad request to the browser. This automatic model state checking happens due to [ApiController] attribute. Since the framework is detecting the error before reaching the the Post() action, the breakpoint will not be reached.

The following figure shows how the browser is sent a 400 - Bad Request message.

Notice how the validation error message from the validation attributes is available to the client via responseText property in addition to status and statusText properties.

That's for now! Keep coding!!


Bipin Joshi is a software consultant, trainer, author and spiritual yoga mentor having 23+ years of experience in software development. He teaches online training courses in ASP.NET Core, Angular, and Design Patterns to individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 01 October 2018


Tags : ASP.NET ASP.NET Core MVC C# JavaScript