How to automatically validate a model with MVC filter and Fluent Validation package
Published: 2021-06-10 20:16:59

I have had the opportunity to see many MVC projects and in the vast majority of them I find structures where the view models are manually validated in all the methods of all the controllers.

At best, the code relies on verifying *ModelState* property from Controller class, but in the worst case… better not to comment it.

```csharp
[Route("")]
[HttpPost]
public async Task<IActionResult> CreatePostAsync([FromBody] CreatePost request)
{
    if (ModelState.IsValid)
    {
        return Ok(await _postService.CreateAsync(request));
    }
    return BadRequest(ModelState.ValidationState);
}
```
So, it exists a more elegant solution for this… let’s see it

*In our example, we will validate a view model called CreatePost before the request reaches the controller PostController, and after that, we will send the request to properly service*

**Step 1: Install nuget packages**

- [FluentValidation.AspNetCore](https://www.nuget.org/packages/FluentValidation.AspNetCore/) by [Jeremy Skinner](https://github.com/JeremySkinner)

**Step 2: Create validator**

With FluentValidation package, all our validators are classes that inherits from AbstractValidator<T>, where <T> is our view model.

In this step, we’re making sure that the “Title” and “Content” properties from “CreatePost” view model are never empty, like [[Required]](https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/adding-validation-to-the-model) data annotation.

```csharp
public class CreatePostValidator : AbstractValidator<CreatePost>
{
    public CreatePostValidator()
    {
        RuleFor(x => x.Title).NotEmpty();
        RuleFor(x => x.Content).NotEmpty();
    }
}
```
As you can see, in class constructor, you can add rules for each property and combine as you need.

*This is a more complete example with conditional rules for a more flexible scenario, where we can allow authentication with a username or email, but always one of the two.*

```csharp
public class LoginValidator : AbstractValidator<Login>
{
    public LoginValidator()
    {
        RuleFor(x => x.UserName)
            .NotEmpty()
            .When(x => !DataTypesHelper.IsEmail(x.Email) && string.IsNullOrEmpty(x.Email))
            .WithMessage("Username or email are required");

        RuleFor(x => x.Email)
            .NotEmpty()
            .When(x => string.IsNullOrEmpty(x.UserName))
            .WithMessage("Username or email are required");

        RuleFor(x => x.Password)
            .NotEmpty()
            .WithMessage("Password is required");
    }
}
```

If you need, you can read the complete documentation about FluentValidation from [Github repository](https://github.com/JeremySkinner/FluentValidation/wiki/b.-Creating-a-Validator).

**Step 3: Create MVC filter**

As shown on this post about [MVC lifecycle](https://exceptionnotfound.net/the-asp-net-web-api-2-http-message-lifecycle-in-43-easy-steps-2/) by [Matthew Jones](https://twitter.com/ExceptionFound), Action Filters are invoked before and after controller, but we are interested in validating our model only before invoking the controller, so for this reason we will use *OnActionExecuting* method.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fllfa9iee4635noeyyh.png)[https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf](https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf)

At this point, we will check *ModelState*, which internally will apply the rules that we have defined with FluentValidation

```csharp
public class ModelStateFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }
    public void OnActionExecuted(ActionExecutedContext context) { }
}
```

Code example is based on this [Gist](https://gist.github.com/Ciantic/88a2e9bae6961c23c2f366e89526b853)

**Step 4: Register services into DI container**

When adding the MVC service to the DI container, we must specify the action filters that we want to use, and then, specify in which assembly are the validators of our view models.

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
        {
            options.Filters.Add(new ModelStateFilter());
        })
        .AddFluentValidation(options =>
        {
            options.RegisterValidatorsFromAssemblyContaining<Startup>();
        });
}
```
**Step 5: Create controller method**

The last step is to create a method in our controller, which meets the requirement of being lightweight.

```csharp
[Route("")]
[HttpPost]
public async Task<IActionResult> CreatePostAsync([FromBody] CreatePost request)
{
    return Ok(await _postService.CreateAsync(request));
}
```

If you invoke the method with the wrong view model, you will receive a response like “400 Bad Request” with the errors summary.

```shell
POST /post HTTP/1.1
Host: localhost:50555
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c5f7b803-dfe2-a315-eb8f-671b84cb3175

{
	"Title": "",
	"Content": "",
	"Excerpt": ""
}
```

```json
{
    "Title": [
        "'Title' should not be empty."
    ],
    "Content": [
        "'Content' should not be empty."
    ]
}
```

Notice: [This post was published originally on Medium platform on may 2, 2018](https://medium.com/@sergiobarriel/how-to-automatically-validate-a-model-with-mvc-filter-and-fluent-validation-package-ae51098bcf5b)