Fluent Validation MVC – dobre bo proste
Jeśli zajmujesz się aplikacjami webowymi w ASP.NET MVC to prawie na pewno trafiłeś na problem sprawdzania poprawności przesyłanych w formularzu danych. W takim wypadku sporo poradników w internecie rozpisuje się o dostępnych w .NET adnotacjach, które możemy dodawać do poszczególnych pól modelu i dzięki temu w akcji obsługującej przysłane dane sprawdzić prostym warunkiem if(ModelState.IsValid){ /*…*/ } czy to co przyszło jest ok. Jednak z biegiem czasu doszedłem do wniosku, że o ile takie nakładanie warunków sprawdza się do małych modeli i typowych przypadków to już zwalidowanie większego formularza lub konieczność sprawdzenia bardziej złożonych warunków powoduje, że w klasie modelu atrybutów i funkcji pomocniczych jest więcej niż samych pól z danymi, tym bardziej, że nierzadko oprócz atrybutów dotyczących walidacji dodajemy też te odpowiedzialne np. za wyświetlanie pola na stronie. Zaciemnia to znacząco podgląd klasy przez co bardzo trudno szybko zobaczyć czy nie brakuje nam jakiegoś pola lub jakiego typu jest to, które akurat jest potrzebne.
Dosyć długo sądziłem, że trzeba się pogodzić z tym, że jest to tak zrobione i nie znałem żadnej alternatywy. Mój stan wiedzy i jakość pracy znacząco się poprawiły po ostatnim spotkaniu KGD.NET gdzie dowiedziałem się o sprytnej bibliotece Fluent Validation. Pozwala ona w prosty sposób dodawać walidatory do całych modeli przez co logikę związaną z nakładaniem ograniczeń na pola można całkowicie oddzielić od pliku z klasą. Dodatkowo Fluent Validation udostępnia spory zestaw typowych warunków np. „większe”, „mniejsze”, „nie puste”, „z przedziału”, ale też np. takie jak sprawdzanie czy tekst jest emailem. Jeśli typowe warunki nie wystarczą można też użyć własną funkcję zwracającą prawda/fałsz dzięki temu nawet najbardziej skomplikowane warunki mogą być nałożone w prosty do czytania i modyfikacji sposób. A skoro są warunki to i są zwykle informacje o błędzie, które użytkownik widzie kiedy źle wypełni formularz. Fluent Validation również tutaj sporo pomaga bo do każdej reguły, którą napiszemy możemy dodać własną wiadomość zwracają w przypadku niepowodzenia walidacji. Dodatkowo czytelność zapisu poprawia używanie fluent API (od którego pewnie wzięła się nazwa) przez co reguły czyta się wręcz jak zwykłe zdania.
W tym wpisie pokażę konkretnie Fluent Validation MVC czyli bibliotekę Fluent Validation przystosowaną do użycia we frameworku ASP.NET MVC. Zakładam, że wiesz jak wygląda standardowa walidacja w ASP.NET MVC korzystająca z atrybutów dodawanych do pól klasy i wiesz w jaki sposób zwraca się użytkownikowi niepoprawnie uzupełniony formularz wraz z komunikatami o błędach. Bibliotekę można poprać przy użyciu NuGeta dzięki temu dodanie jej do projektu jest bardzo proste i sprowadza się do znalezienia za pomocą wyszukiwarki odpowiedniej pozycji. Kiedy już zainstalujemy Fluent Validation MVC w naszym projekcie to trzeba ją uruchomić. W tym celu wystarczy otworzyć plik Global.asax.cs i w metodzie Application_Start() dopisać linijkę
FluentValidationModelValidatorProvider.Configure();
I tyle. W tym momencie biblioteka do walidacji będzie działała w aplikacji i jedyne co zostało to dopisanie odpowiednich walidatorów dla modeli i obsłużenie sprawdzania poprawności danych w akcji kontrolera.
Jeśli chodzi o obsługę błędnych danych w kontrolerze i widoku to wystarczy skorzystać ze standardowych konstrukcji dostępnych w ASP.NET MVC czyli sprawdzanie flagi IsValid w akcji odbierającej dane z formularza ( if(ModelState.IsValid) { /* … */ } ) i dodanie dla pól w widoku wiadomości z błędem pojawiającej się kiedy akcja zwróci ponownie widok z danymi zawierającymi błędy czyli standardowo @Html.ValidationMessageFor() . Więc jak widać, jeśli wcześniej korzystało się z wbudowanej w ASP.NET MVC walidacji danych to nie ma potrzeby zmieniania praktycznie niczego w kontrolerze i widoku.
Dobra, w takim razie przyszła pora na omówienie najważniejszej części czyli walidatorów dla modeli. Załóżmy, że chcemy napisać dla poniższej klasy walidator, który sprawdzi czy pole name nie jest puste i czy pole size ma wartość większą od 0 w przypadku kiedy pole isEnable ma wartość true. Najpierw przykładowa klasa:
public class MyObject { public string Name { get; set; } public int Size { get; set; } public bool IsEnable { get; set; } }
Teraz pora na walidator. Jest on zwykłą klasą dodaną gdzieś w projekcie, która dziedziczy po klasie generycznej AbstractValidator<>, której podajemy jaki typ chcemy obsługiwać. Bez zbędnego przedłużania i żeby od razu pokazać, że Fluent Validation pozwala pisać pisać kod na tyle czytelny, że nawet bez wyjaśnień zrozumiesz o co w nim chodzi pokażę od razu całą klasę naszego walidatora, który będzie odpowiedzialny za sprawdzanie podanych wcześniej warunków:
public class MyObjectValidator : AbstractValidator<MyObject> { public MyObjectValidator() { RuleFor(x => x.Name).NotEmpty(); RuleFor(x => x.Size).GreaterThan(0).When(x => x.IsEnable); } }
Myślę, że od razu umiesz określić co robią poszczególne fragmenty, ale tylko dla formalności powiem, że w pierwszej linii w konstruktorze sprawdzamy czy pole Name nie jest puste, zaś w drugiej sprawdzany jest warunek mówiący, że pole Size powinno być większe od 0 jeśli pole IsEnable ma wartość true. Ostatnia rzecz jaka nam została to dodanie odpowiedniego atrybutu do klasy naszego modelu. Wracamy więc do naszej klasy MyObject i nad nazwą klasy dopisujemy
[Validator(typeof(MyObjectValidator))]
Jako argument podajemy typ naszego walidatora. I w tym momencie to już absolutnie wszystko co musimy zrobić, żeby Fluent Validation sprawdzało podstawowe warunki dla pól naszego modelu. Jeśli teraz uruchomisz aplikację i wypełnisz formularz z danymi do modelu w niespełniający podanych przez nas warunków sposób, czyli np. pozostawiając pole Name puste to po próbie wysłania go powinieneś dostać taką samą informację jak w przypadku dodania do pola atrybutu [Required].
To tyle jeśli chodzi o przedstawienie Wam fajnej, wygodnej biblioteki jaką jest Fluent Validation. To co pokazałem to oczywiście same podstawy jednak pozwalają zacząć zabawę z biblioteką. Sam powoli zaczynam ją stosować, nie znam na pewno jeszcze niektórych jej możliwości, ale już widzę, że całość ma potencjał i jeśli tylko to co będę robił nie będzie bardzo dziwnym tworem zahaczającym o rocket science to myślę, że Fluent Validation będzie w 100% użyteczne i wygodne. Jeśli chcecie dowiedzieć się więcej o konstruowaniu warunków w tej bibliotece to zapraszam do dokumentacji znajdującej się na jej stronie.
Leave a Comment