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?
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.
领英推荐
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:
Because?Price?was not provided when?Quantity?is greater than zero, an error message occurs:
The model is validated and the error message is displayed, as expected.
MSC cs Algorithm student | .Net Developer
2 年Very helpful thnak you????