FluentValidation – integracja z ASP.NET MVC

W dzisiejszym poście pokażę jak zintegrować FluentValidation z ASP.NET MVC5, na podstawie dodawania użytkownika.

Po za standardowym FluentValidation potrzebujemy również FluentValidation.MVC5. Ta biblioteka zapewnia ModelValidatorProvider odpowiedni dla FluentValidation.

Install-Package FluentValidation
Install-Package FluentValidation.MVC5

Następnie w miejscu startu aplikacji (u mnie jest to Application_Start Global.asax) dodajemy taki fragment kodu:

FluentValidationModelValidatorProvider.Configure();

Sprawia on, że od tej pory nasz framework webowy nie będzie korzystał w wbudowanej walidacji przez DataAnnotations, tylko z FluentValidation.

Teraz utwórzmy model klasy walidowanej:

[Validator(typeof(UserViewModelValidator))]
public class UserViewModel
{
    public string UserName { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }
}

Widzimy, że w porównaniu do modelu z poprzedniego posta, różni się on atrybutem Validator. Ten atrybut mówi ASP.NET, że gdy będzie chciał zwalidować obiekt tej klasy, to powinien użyć do tego walidatora z atrybutu.

Walidator:

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);
    }
}

W HomeController dodajemy prosty kod mający symulować dodawanie użytkownika do bazy danych. Gdy dane nie przejdą walidacji to zwracamy widok wraz z tymi danymi. W przeciwnym wypadku przekierowujemy na stronę UserCreated.

[HttpPost]
public ActionResult CreateUser(UserViewModel user)
{
    if (!ModelState.IsValid)
        return View(user);
            
    // add user to database

    return View("UserCreated");
}

Został tylko formularz dodawania użytkowników w HTML. Pod każdym polem formularz używamy ValidationMessageFor, aby pokazać błędy walidacyjne, jakie zwróci kontroler.

<h4>Create a new user.</h4>

<div class="form-group">
    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(m => m.UserName, string.Empty, new { @class = "text-danger" })
</div>

<div class="form-group">
    @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(m => m.Email, string.Empty, new { @class = "text-danger" })
</div>

<div class="form-group">
    @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(m => m.Password, string.Empty, new { @class = "text-danger" })
</div>

<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" class="btn btn-default" value="Create" />
    </div>
</div>

Po uruchomieniu naszej aplikacji i wpisaniu błędnych danych pojawia się taki o to widok:

FluentValidationMVC

Czyli nasza walidacja działa i nieprawidłowe dane zostały zwrócone do użytkownika w celu ich poprawienia.

Walidacja wewnętrznych klas

Integracja pomiędzy ASP.NET i FluentValidation pozwala na bardzo prostą walidację klas, które są polami naszej głównej klasy. Powiedzmy, że do naszego użytkownika dodajemy pole odpowiedzialne za składowanie informacji o jego adresie. Aby zwalidować taki zagłebiony obiekt należy jedynie powtórzyć powyższe kroki dla klasy adresu. Framework przejdzie po wszystkich polach obiektu walidowanego i jeśli to pole jest połączone z walidatorem, to użyje go by zwalidować ten obiekt. Całość przedstawia się tak:

Model użytkownika rozszerzony o pole adresu:

[Validator(typeof(UserViewModelValidator))]
public class UserViewModel
{
    public string UserName { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }

    public AddressViewModel Address { get; set; }
}

Model adresu i jego walidator.

[Validator(typeof(AddressViewModelValidator))]
public class AddressViewModel
{
    public string City { get; set; }

    public string PostalCode { get; set; }
}
public class AddressViewModelValidator : AbstractValidator<AddressViewModel>
{
    public AddressViewModelValidator()
    {
        this.RuleFor(r => r.City).NotEmpty().Length(1, 50);

        this.RuleFor(r => r.PostalCode).NotEmpty().Matches("^[0-9]{2}-[0-9]{3}$");
    }
}

I rezultat:
FluentValidationMVC2

Podsumowanie

Biblioteka FluentValidation w prosty sposób łączy się z ASP.NET MVC, przez co już w kilka chwil możemy korzystać z niej w naszej aplikacji webowej. Dodawanie kolejnych walidatorów jest szybkie i nie wpływa na zmianę dotychczasowej logiki przetwarzania żądań w MVC. Wszystko dzieje się pod spodem, a my tylko korzystamy z dobrodziejstw FluentValidation.

Standardowo, wszystkie pokazane tutaj przykłady są na GitHubie.

  • Pingback: dotnetomaniak.pl()

  • Pingback: FluentValidation – integracja z ASP.NET Web API | RadBlog()

  • http://abcdw.pl/ Krzysztof Wiśniewski

    Wszystkie trzy artykuły o fluent validation napisane niezwykle przystępnie. Wielkie dzieki za inspirację. Mam nadzieję, że jutro sam potestuję :)

    • Radosław Maziarka

      Jakbyś miał z czymś problemy to daj znać na maila to bym o tym posta napisał. Aktualnie mam w planach jeszcze opis DI, lokalizację komunikatów i warunkową walidację.