DEV Community

Cover image for Validation in .NET Core
ISeeSharp
ISeeSharp

Posted on

Validation in .NET Core

Introduction

In .NET Core, validation refers to the process of checking that the data provided by the user or client is in the correct format and meets the requirements of the application. This can include checks for things like required fields, minimum and maximum values, and correct data types.

To perform validation in a .NET Core API, you can use the built-in ModelState class and the [Required], [Range], and [RegularExpression] attributes. Here is an example of how these can be used to validate the data provided by the user in a controller action:

public IActionResult CreateUser([FromBody] User user)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // Save the user to the database and return a success response...
}
Enter fullscreen mode Exit fullscreen mode

In this example, the CreateUser action method accepts a User object as an argument. The [FromBody] attribute is used to indicate that the User object will be provided in the request body. The if statement at the beginning of the method checks the ModelState to see if the data provided by the user is valid. If the ModelState is not valid, the BadRequest method is called to return an error response to the user.

The User class itself might look like this:

public class User
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    [Range(1, 100)]
    public int Age { get; set; }

    [Required]
    [RegularExpression("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$")]
    public string Email { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In this User class, the [Required] attribute is used to indicate that the FirstName, LastName, Age, and Email properties are required and must be provided by the user. The [Range] attribute is used to specify that the Age property must be a number between 1 and 100. Finally, the [RegularExpression] attribute is used to specify that the Email property must match a certain pattern (in this case, a valid email address).

When the CreateUser action method is called, the ModelState will be checked to ensure that the data provided by the user is valid. If any of the required properties are missing or if any of the properties have invalid values (e.g. if the Age property is not a number between 1 and 100, or if the Email property does not match the specified pattern), the ModelState will be considered invalid and an error response will be returned to the user. Otherwise, the user will be saved to the database and a success response will be returned.

Using [ApiController] to replace the ModelState check

To use the [ApiController] attribute, you simply need to add it to the top of the UsersController class, like this:

[ApiController]
public class UsersController : ControllerBase
Enter fullscreen mode Exit fullscreen mode

This attribute indicates that the UsersController class is an API controller, which enables certain features and behaviors that are specific to API controllers in .NET Core. For example, when the [ApiController] attribute is applied to a controller, the ModelState will automatically be checked for validation errors before any action method in the controller is called, and an error response will be returned to the user if any validation errors are found. This means that you don't need to manually check the ModelState in each action method, as the attribute will handle it for you.

Additionally, the [ApiController] attribute enables the use of HTTP 400 responses for validation errors, rather than the default HTTP 500 responses. This means that when the [ApiController] attribute is applied to a controller, if any validation errors are found, the BadRequest method will automatically be called to return an HTTP 400 response to the user, rather than the InternalServerError method being called to return an HTTP 500 response. This behavior can make it easier to understand and handle validation errors in your API.

For more C# and Dotnet content see my Youtube channel: https://www.youtube.com/channel/UCfZF4WWaH4i13MzEICLt6sQ

Top comments (4)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

ModelState.IsValid falls in the category of RAD things Microsoft does to keep average programmers interested in .Net.

Controllers have no business validating data as per the rules of layered software architecture and SOLID principles. Since .Net is strongly-typed, I guess we have to live with the minimal check done when ASP.Net attempts to deserialize the HTTP request data into .Net structures. But that's about it.

Properly coded ASP.Net servers should avoid all use of ModelState and instead program data validation inside the inner business layers.

Collapse
 
iseesharp profile image
ISeeSharp

Thank you for the info! This is not something I have heard about before do you have any links where I can find more info about why validation in controllers is a problem?

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

I have no links because nobody has written about this. I'll probably be the first. Will let you know once this happens. Maybe you'll be the first to read about it. :-)

Quickly, though:

  1. SOLID: A controllers single responisibility is to deserialize incoming data and serialize outgoing data using the HTTP protocol. That's it. No more responsibilities to controllers or you'll violate the S in SOLID.
  2. Layered Architecture: Any layer should be replaceable without having to re-write code in the remaining layers. If you remove the HTTP layer (controllers), you will be losing data validation. Therefore, coupling data validation with data serailization/deserialization is a bad idea.

So why ModelState exists? Microsoft has a history of providing quick-n-easy stuff that cuts corners in software design to entice developers to use .Net. ModelState is one of them.

Thread Thread
 
iseesharp profile image
ISeeSharp

Thank you for your response this is something I will have a think about for my next api project.

I would definitely like to read an article on this topic if you write one!