Integracja FluentValidation z Minimal API w .NET
To ostatni artykuł z cyklu poświęconego FluentValidation
. Rozpoczniemy od przybliżenia dwóch podstawowych sposobów rejestrowania walidatorów w aplikacjach .NET za pomocą mechanizmu wstrzykiwania zależności. Omówione zostaną metody umożliwiające rejestrację dedykowanych walidatorów oraz wykorzystanie pakietu FluentValidation.DependencyInjectionExtensions
, który znacznie upraszcza i automatyzuje proces rejestracji walidatorów.
Dodatkowo pokażemy, jak używać zarejestrowanych walidatorów w Minimal API, co pozwala na przejrzyste i efektywne zarządzanie walidacją danych wejściowych w nowoczesnych projektach. W artykule zostanie omówione również zarządzanie cyklem życia rejestrowanych walidatorów. Zapraszam do czytania.
Rejestrowanie określonego walidatora
Walidatory FluentValidation
można z łatwością zintegrować z różnorodnymi bibliotekami odpowiedzialnymi za wstrzykiwanie zależności, w tym z popularną biblioteką Microsoft.Extensions.DependencyInjection
. Proces integracji walidatora dla konkretnego typu modelu danych jest prosty i przejrzysty. Polega na zarejestrowaniu walidatora w dostawcy usług. Kluczowym krokiem jest zadeklarowanie walidatora jako typu IValidator<T>
, gdzie T
reprezentuje konkretny typ obiektu, który ma zostać poddany walidacji. Dzięki temu podejściu walidator staje się dostępny w całym systemie jako usługa, co pozwala na łatwe i elastyczne zarządzanie procesami walidacji danych.
builder.Services.AddTransient<IValidator<SomeModel>, SomeModelValidator>();
W powyższym przykładzie, SomeModelValidator
jest jawnie zarejestrowany jako walidator dla typu SomeModel
.
Użycie pakietu FluentValidation.DependencyInjectionExtensions
znacznie upraszcza proces rejestracji walidatorów, oferując metody rozszerzające, które automatyzują skanowanie i rejestrowanie walidatorów w kontenerze usług. Aby skorzystać z tej metody, najpierw dodaj pakiet do projektu:
dotnet add package FluentValidation.DependencyInjectionExtensions
Po dodaniu pakietu dostępne stają się metody rozszerzające takie jak AddValidatorsFromAssemblyContaining
, które pozwalają na zautomatyzowaną rejestrację wszystkich walidatorów zdefiniowanych w danym zestawie. Możesz wybrać spośród kilku przeciążeń tej metody, aby dostosować proces rejestracji do swoich potrzeb, włączając możliwość ustawienia zakresu życia walidatorów na Singleton
, Scoped
lub Transient
.
// Overload 1 - To Register all the validators
builder.Services.AddValidatorsFromAssemblyContaining(typeof(StudentValidator));
// Overload 2 - To Register all the validators
builder.Services.AddValidatorsFromAssemblyContaining<StudentValidator>();
// Overload 3 - To Register all the validators
builder.Services.AddValidatorsFromAssemblyContaining<StudentValidator>(ServiceLifetime.Scoped);
Korzystając z tych metod, możesz znacznie upraszczać zarządzanie walidacjami w swoich aplikacjach, jednocześnie zachowując wysoką elastyczność i kontrolę nad procesem.
Czas życia walidatorów
Zasadniczo, zaleca się rejestrowanie walidatorów FluentValidation
jako Transient
, co jest najbezpieczniejszą i najprostszą opcją. Taki zakres zapewnia, że każda operacja walidacji korzysta z nowej, niezależnej instancji walidatora, eliminując tym samym ryzyko związane z dzieleniem stanu między operacje.
Rejestracja walidatora jako Singleton
wymaga szczególnej ostrożności. W takim przypadku powinniśmy unikać wstrzykiwania do walidatora zależności o zakresie Transient
lub Scoped
,Singleton
nie jest zalecane, chyba że mamy doświadczenie w korzystaniu ze wstrzykiwania zależności i wiemy, jak rozwiązywać problemy wynikające z posiadania zależności o różnych zakresach przez obiekty o zakresie Singleton
.
Podsumowując, choć istnieje możliwość ustawienia różnych zakresów życia dla walidatorów, najczęściej sugerowanym i najbezpieczniejszym podejściem jest wykorzystanie zakresu Transient
, szczególnie jeśli chcemy uniknąć potencjalnych pułapek związanych z zarządzaniem zależnościami.
Użycie FluentValidation w Minimal API
Po zarejestrowaniu walidatorów możemy je łatwo używać bezpośrednio w endpointach minimal API. Poniżej znajduje się przykładowa implementacja, która pokazuje, jak wykorzystać zarejestrowany walidator w minimal API. Najpierw zdefiniujmy model User
oraz walidator UserValidator
:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(x => x.FirstName).NotEmpty().WithMessage("First name is required");
RuleFor(x => x.LastName).NotEmpty().WithMessage("Last name is required");
RuleFor(x => x.Email).EmailAddress().WithMessage("A valid email is required");
RuleFor(x => x.Age).InclusiveBetween(18, 60).WithMessage("Age must be between 18 and 60");
}
}
Dodajmy endpoint do minimal API, który wykorzystuje zarejestrowany walidator:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddValidatorsFromAssemblyContaining<UserValidator>();
var app = builder.Build();
app.MapPost("/users", async (IValidator<User> validator, User user) =>
{
ValidationResult validationResult = await validator.ValidateAsync(user);
if (!validationResult.IsValid)
{
return Results.ValidationProblem(validationResult.ToDictionary());
}
// ...
});
app.Run();
Powyższy kod pokazuje, jak używać FluentValidation
w minimal API. Walidacja odbywa się bezpośrednio w endpointach API, co pozwala na przejrzyste i łatwe zarządzanie walidacją danych wejściowych. W razie niepowodzenia walidacji, API zwraca odpowiednią odpowiedź z błędami walidacji.
Podsumowanie
W artykule przedstawiono metody integracji walidatorów FluentValidation
z aplikacjami .NET, wykorzystując mechanizm wstrzykiwania zależności. Zostały omówione praktyczne aspekty tej integracji, podkreślając, jak ułatwia ona zarządzanie walidacjami w projekcie. Zostało zaznaczone, jak kluczowe jest rejestrowanie dedykowanych walidatorów oraz jakie korzyści płyną z użycia pakietu FluentValidation.DependencyInjectionExtensions
, który automatyzuje i upraszcza proces integracji.
W artykule podkreślono także wagę odpowiedniego zarządzania czasem życia walidatorów, rekomendując zakres Transient
dla zapewnienia maksymalnej niezawodności i minimalizacji ryzyka błędów związanych ze stanem współdzielonym. Zostały przedstawione potencjalne pułapki związane z użyciem zakresu Singleton
oraz konieczność unikania mieszania zakresów życia zależności.
Dodatkowo omówiono szczegóły integracji FluentValidation
z Minimal API, pokazując, jak używać zarejestrowanych walidatorów bezpośrednio w endpointach. Przykłady kodu ilustrują, jak przeprowadzać walidację danych wejściowych w minimal API oraz jak odpowiednio reagować na błędy walidacji, zwracając odpowiednie odpowiedzi HTTP.
Podsumowując, dzięki dogłębnemu zrozumieniu omówionych koncepcji i skutecznemu wykorzystaniu dostępnych narzędzi, można efektywnie wdrażać walidatory FluentValidation
, co przekłada się na solidność, spójność i łatwość w zarządzaniu procesami walidacji w aplikacjach .NET Core, w tym również w nowoczesnych projektach opartych na minimal API.