W poprzednim poście z cyklu FluentValidation pokazałem jak dodać FluentValidation do ASP.NET MVC. W takim razie pora na pokaz integracji z ASP.NET Web API.
Zaczynamy od dodania do naszego projektu biblioteki łączącej FluentValidation z WebApi.
Install-Package FluentValidation.WebAPI
Następnie w miejscu startu aplikacji (u mnie jest to Application_Start Global.asax) dodajemy kod odpowiedzialny za połączenie FluentValidation z domyślną walidacją WebAPI.
FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration);
W przypadku używania FluentValidation także z MVC może wystąpić problem z identycznymi nazwami klas przez co trzeba się posiłkować dodaniem przedrostka przestrzeni nazw.
Do walidacji użyjemy tego samego modelu i walidatora, co w poprzednim poście:
[Validator(typeof(UserViewModelValidator))]
public class UserViewModel
{
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class UserViewModelValidator: AbstractValidator<UserViewModel>
{
public UserViewModelValidator()
{
this.RuleFor(r => r.UserName).NotEmpty().Length(0, 50);
this.RuleFor(r => r.Email).NotEmpty().EmailAddress().Length(0, 100);
this.RuleFor(r => r.Password).NotEmpty().Length(6, 50);
}
}
Następnie stwórzmy prosty kontroler zwracający informacje o nieudanej walidacji użytkownika, w przypadku błędów walidacji:
public class UserController : ApiController
{
public HttpResponseMessage PostUser(UserViewModel user)
{
if (!ModelState.IsValid)
{
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.BadRequest,
Content = new StringContent("Validation failed.")
};
}
// create user
return this.Request.CreateResponse(HttpStatusCode.Created);
}
}
Uruchamiając Postmana i wysyłając proste żądanie dostajemy poprawną odpowiedź:
Czyli nasza walidacja działa - dostajemy błąd HTTP 400 i komunikat błędu.
Filtr walidacyjny
Aby uprościć sobie życie i nie dodawać za każdym razem sprawdzania walidacji w akcji kontrolera proponowałbym stworzenie prostego filtra walidacyjnego. Miałby on za zadanie podpięcie się przed wykonaniem metody i sprawdzenie czy model jest poprawny. Kiedy zachodzi problem walidacji modelu, zwracamy odpowiednią dla nas wiadomość - może to być prosta lista błędów, ale nic nie szkodzi nam na przeszkodzie by pogrupować te błędy i zwrócić bardziej skomplikowany obiekt. Moja implementacja filtra:
public class ModelStateFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
var errors = actionContext.ModelState
.Values.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage);
actionContext.Response =
actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errors);
}
}
}
Postawiłem na prostotę. Dziedziczę po klasie _ActionFilterAttribute, która umożliwia podpięcie się pod akcje kontrolera. _W metodzie _OnActionExecuting _sprawdzam, czy _ModelState _jest prawidłowy. Jeśli nie, to iteruję po wszystkich błędach i zwracam je jako listę do użytkownika. W takim przypadku metoda kontrolera się bardzo upraszcza:
public HttpResponseMessage PostUser(UserViewModel user)
{
// create user
return this.Request.CreateResponse(HttpStatusCode.Created);
}
Nie potrzebujemy dodatkowego kodu walidacyjnego - wszystko załatwia nam filtr. Zostaje tylko podpiąć nasz filtr do WebAPI - u mnie dzieje się to w pliku WebApiConfig.
config.Filters.Add(new ModelStateFilterAttribute());
Dzięki temu, przy identycznym żądaniu z Postmana, dostajemy listę błędów modelu.
Podsumowanie
Dodanie FluentValidation do _ASP.NET WebAPI _nie różni się skomplikowaniem od dodania integracji do _ASP.NET MVC _ - jest równie proste. Z pomocą filtrów jesteśmy w stanie uprościć proces walidacji, przez co nie dodajemy dodatkowego kodu w naszych kontrolerach. Kod jest o wiele czystszy i czytelniejszy.
Standardowo, wszystkie pokazane tutaj przykłady są na GitHubie.
Comments:
FluentValidation – integracja z ASP.NET Web API | RadBlog
Dziękujemy za dodanie artykułu - Trackback z dotnetomaniak.pl