Fluent Validation in .NET 6

Fluent Validation in .NET 6

The Problem

Data Validation is extremely vital for any Application. The GO-TO Approach for Model validation in any .NET Application is Data Annotations, where you have to declare attributes over the property of models. Worked with it before?

public class Develope
    {
       [Required]
        public string FirstName { get; set; }
        [Required]
        public string LastName { get; set; }
        [EmailAddress]
        public string Email { get; set; }
        [Range(minimum:5,maximum:20)]
        public decimal Experience { get; set; }
    }r        

It is fine for beginners. But once you start learning clean code, or begin to understand the SOLID principles of application design, you would just never be happy with Data Annotations as you were before. It is clearly not a good approach to combine your models and validation logic.

With the implementation of Data Annotations in .NET Classes, the problem is that there will be a lot of duplication lines of code throughout your application. What if the Developer Model class is to used in another application/method where these Attribute validation changes? What if you need to validate a model that you don’t have access to? Unit testing can get messy as well. You will definitely end up build multiple model classes which will no longer be maintainable in the longer run. So, what’s the solution?

Introducing?Fluent Validation – The Solution

Fluent Validation?is a free to use .NET validation library that helps you make your validations clean, easy to create, and maintain. It even works on external models that you don’t have access to, with ease. With this library, you can separate the model classes from the validation logic like it is supposed to be. It doesn’t make your Model classes ugly like Data Annotations does. Also, better control of validation is something that makes the developers prefer Fluent Validation.

Fluent validations uses?lamba expressions?to build validation rules.

For small systems, I would recommend just using Data Annotations, because they’re so easy to set up. For larger, more complex systems, I would recommend separating the validation concern using validator objects with Fluent Validation.

Fluent Validation is a validation library available as a NuGet package, that can be easily implemented by developers. It uses a fluent API that leverages lambda expressions to validate rules.

What are the benefits of Fluent Validation?

  • It uses the Fail Fast principle.
  • Validation with errors, instead of exceptions.
  • Rules are centralized on validators.
  • Unit Testable

Nuget Packages

In this example we use?FluentValidation.AspNetCore, but in Libraries?FluentValidation?is also an option.

Sample

The solution has a POST endpoint that allows users to submit a Product. The Fluent Validation is executed on the request, and in case it fails, it returns a?BadRequest.

No alt text provided for this image

Program.cs:

using FluentValidation.AspNetCore

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddFluentValidation(conf =>
{
    conf.RegisterValidatorsFromAssembly(typeof(Program).Assembly);
    conf.AutomaticValidationEnabled = false;
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthorization();

app.MapControllers();

app.Run();;        

As the package is added, the?AddFluentValidation?extension is added to the Service Collection. It is necessary to register the validators using?RegisterValidatorsFromAssembly. The?AutomaticValidationEnabled?was set to false, so we can control the validation when debugging the solution. If you don't do that, ASP.NET validation occurs automatically by default, at the time of model binding.

ProductViewModel.cs

public class ProductViewMode
{
    public string Name { get; set; }
    public string Sku { get; set; }
    public int Quantity { get; set; }
    public double Price { get; set; }
}        

ProductViewModelValidator.cs

public class ProductViewModelValidator : AbstractValidator<ProductViewModel>
{
    public ProductViewModelValidator()
    {
        RuleFor(model => model.Name).NotNull().NotEmpty().WithMessage("Please specify a name");
        RuleFor(model => model.Sku).NotNull().NotEmpty().Length(3, 10);
        RuleFor(model => model.Quantity).GreaterThanOrEqualTo(0);
        RuleFor(model => model.Price).NotEqual(0).When(model => model.Quantity > 0)
            .WithMessage("Please specify a price");
    }
}        

In here some validations were added to the?ProductViewModel. We check whether the properties are not null, not empty, we specify error messages, having the minimal length of 3 and max length of 10, value is greater than or equal to zero, and also a property validation based on property value.

Looking at the controller, the validation happens within the POST method:

[ApiController]
[Route("[controller]")]
public class ProductController : Controller
{
    private readonly IValidator<ProductViewModel> _validator;

    public ProductController(IValidator<ProductViewModel> validator)
    {
        _validator = validator;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] ProductViewModel model)
    {
        var validation = await _validator.ValidateAsync(model);

        if (!validation.IsValid)
        {
            return BadRequest(validation.Errors?.Select(e => new ValidationResult()
            {
                Code = e.ErrorCode,
                PropertyName = e.PropertyName,
                Message = e.ErrorMessage
            }));
        }

        return Ok();
    }
}        

Running the solution

Run the solution and open Swagger to perform the POST:

No alt text provided for this image

Because?Price?was not provided when?Quantity?is greater than zero, an error message occurs:

No alt text provided for this image

The model is validated and the error message is displayed, as expected.

Mohammad Mahdi Nomani

MSC cs Algorithm student | .Net Developer

2 年

Very helpful thnak you????

要查看或添加评论,请登录

Chia Karimi的更多文章

  • Implementing CQRS with MediatR in .NET6

    Implementing CQRS with MediatR in .NET6

    CQRS and the Mediator Pattern The MediatR library was built to facilitate two primary software architecture patterns:…

    3 条评论
  • Zen coding

    Zen coding

    ?? ????? ???? ?? ???? Zen coding https://www.smashingmagazine.

社区洞察

其他会员也浏览了