Dodawanie walidacji
Autor: Rick Anderson
Uwaga
Zaktualizowana wersja tego samouczka jest dostępna tutaj przy użyciu najnowszej wersji programu Visual Studio. W nowym samouczku jest używany ASP.NET Core MVC, który oferuje wiele ulepszeń w tym samouczku.
W tym samouczku przedstawiono ASP.NET Core MVC z kontrolerami i widokami. Platforma Razor Pages to nowa alternatywa dla platformy ASP.NET Core— oparty na stronach model programowania, który ułatwia tworzenie internetowego interfejsu użytkownika i wydajniejsze. Zalecamy wypróbowanie samouczka razor Pages przed wersją MVC. Samouczek razor Pages:
- Jest łatwiejsze do naśladowania.
- Obejmuje więcej funkcji.
- Jest preferowanym podejściem do tworzenia nowych aplikacji.
W tej sekcji dodasz logikę walidacji do Movie
modelu i upewnisz się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik spróbuje utworzyć lub edytować film przy użyciu aplikacji.
Utrzymywanie suchych rzeczy
Jednym z podstawowych zestawów projektu ASP.NET MVC jest DRY ("Nie powtarzaj siebie"). ASP.NET MVC zachęca do określenia funkcjonalności lub zachowania tylko raz, a następnie ich odzwierciedlenia wszędzie w aplikacji. Zmniejsza to ilość kodu potrzebnego do zapisania i sprawia, że kod, który zapisujesz mniej podatny na błędy i ułatwia konserwację.
Obsługa walidacji zapewniana przez ASP.NET MVC i Entity Framework Code First jest doskonałym przykładem zasady DRY w działaniu. Reguły walidacji można deklaratywne określić w jednym miejscu (w klasie modelu), a reguły są wymuszane wszędzie w aplikacji.
Przyjrzyjmy się, jak można skorzystać z tej obsługi weryfikacji w aplikacji filmowej.
Dodawanie reguł walidacji do modelu filmu
Zaczniesz od dodania logiki weryfikacji do Movie
klasy.
Otwórz plik Movie.cs. Zwróć uwagę, że System.ComponentModel.DataAnnotations
przestrzeń nazw nie zawiera System.Web
elementu . Funkcja DataAnnotations udostępnia wbudowany zestaw atrybutów weryfikacji, które można deklaratywnie stosować do dowolnej klasy lub właściwości. (Zawiera również atrybuty formatowania, takie jak Typ danych, który pomaga w formatowaniu i nie zapewnia żadnej walidacji.
Teraz zaktualizuj klasęMovie
, aby korzystać z wbudowanych Required
atrybutów , StringLength
RegularExpression i Range
walidacji. Zastąp klasę Movie
następującym kodem:
public class Movie
{
public int ID { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[StringLength(5)]
public string Rating { get; set; }
}
Atrybut StringLength
ustawia maksymalną długość ciągu i ustawia to ograniczenie w bazie danych, dlatego schemat bazy danych ulegnie zmianie. Kliknij prawym przyciskiem myszy tabelę Filmy w Eksploratorze serwera i kliknij polecenie Otwórz definicję tabeli:
Na powyższej ilustracji widać, że wszystkie pola ciągów są ustawione na NVARCHAR (MAX). Użyjemy migracji do zaktualizowania schematu. Skompiluj rozwiązanie, a następnie otwórz okno konsoli Menedżer pakietów i wprowadź następujące polecenia:
add-migration DataAnnotations
update-database
Po zakończeniu tego polecenia program Visual Studio otwiera plik klasy definiujący nową DbMigration
klasę pochodną o określonej nazwie (DataAnnotations
), a w Up
metodzie można zobaczyć kod, który aktualizuje ograniczenia schematu:
public override void Up()
{
AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
}
Pole Genre
nie jest już dopuszczające wartości null (oznacza to, że musisz wprowadzić wartość). Pole Rating
ma maksymalną długość 5 i Title
ma maksymalną długość 60. Minimalna długość 3 w obiekcie Title
i zakres nie Price
utworzył zmian schematu.
Zbadaj schemat filmu:
Pola ciągu pokazują nowe limity długości i Genre
nie są już sprawdzane jako dopuszczane do wartości null.
Atrybuty weryfikacji określają zachowanie, do którego mają być wymuszane właściwości modelu, do których są stosowane. Atrybuty Required
i MinimumLength
wskazują, że właściwość musi mieć wartość, ale nic nie uniemożliwia użytkownikowi wprowadzania białych znaków w celu spełnienia tej weryfikacji. Atrybut RegularExpression służy do ograniczania liczby znaków, które mogą być wprowadzane. W powyższym Genre
kodzie należy Rating
używać tylko liter (białe znaki, cyfry i znaki specjalne są niedozwolone). Atrybut Range
ogranicza wartość do określonego zakresu. Atrybut StringLength
umożliwia ustawienie maksymalnej długości właściwości ciągu i opcjonalnie jego minimalnej długości. Typy wartości (takie jak decimal, int, float, DateTime
) są z natury wymagane i nie wymagają atrybutu Required
.
Code First gwarantuje, że reguły weryfikacji określone w klasie modelu są wymuszane przed zapisaniem zmian w bazie danych przez aplikację. Na przykład poniższy kod zgłosi wyjątek DbEntityValidationException po SaveChanges
wywołaniu metody, ponieważ brakuje kilku wymaganych Movie
wartości właściwości:
MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
db.Movies.Add(movie);
db.SaveChanges(); // <= Will throw server side validation exception
Powyższy kod zgłasza następujący wyjątek:
Walidacja nie powiodła się dla co najmniej jednej jednostki. Aby uzyskać więcej informacji, zobacz właściwość EntityValidationErrors.
Automatyczne wymuszanie reguł walidacji przez program .NET Framework pomaga zwiększyć niezawodność aplikacji. Gwarantuje to również, że nie można zapomnieć o zweryfikowaniu czegoś i przypadkowo niech złych danych w bazie danych.
Interfejs użytkownika błędu walidacji w usłudze ASP.NET MVC
Uruchom aplikację i przejdź do adresu URL /Movies .
Kliknij link Utwórz nowy, aby dodać nowy film. Wypełnij formularz kilkoma nieprawidłowymi wartościami. Gdy tylko walidacja po stronie klienta jQuery wykryje błąd, zostanie wyświetlony komunikat o błędzie.
Uwaga
Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego, należy uwzględnić globalizowanie NuGet zgodnie z opisem wcześniej w tym samouczku.
Zwróć uwagę, że formularz automatycznie użył czerwonego koloru obramowania w celu wyróżnienia pól tekstowych zawierających nieprawidłowe dane i emitował odpowiedni komunikat o błędzie walidacji obok każdego z nich. Błędy są wymuszane po stronie klienta (przy użyciu języków JavaScript i jQuery) i po stronie serwera (w przypadku wyłączenia języka JavaScript przez użytkownika).
Realną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController
klasie ani w widoku Create.cshtml w celu włączenia tego interfejsu użytkownika weryfikacji. Kontroler i widoki utworzone wcześniej w tym samouczku automatycznie podniosły reguły weryfikacji określone przy użyciu atrybutów weryfikacji we właściwościach Movie
klasy modelu. Przetestuj walidację Edit
przy użyciu metody akcji i zastosowano tę samą walidację.
Dane formularza nie są wysyłane do serwera, dopóki nie wystąpią żadne błędy weryfikacji po stronie klienta. Możesz to sprawdzić, umieszczając punkt przerwania w metodzie HTTP Post przy użyciu narzędzia fiddler lub narzędzi deweloperskich IE F12.
Jak odbywa się walidacja w metodzie Create View i Create Action
Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Następna lista pokazuje, jak Create
wyglądają metody w MovieController
klasie. Nie zmieniają się one w sposób, w jaki zostały utworzone wcześniej w tym samouczku.
public ActionResult Create()
{
return View();
}
// POST: /Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
Pierwsza metoda akcji (HTTP GET) Create
wyświetla początkowy formularz Utwórz. Druga wersja ([HttpPost]
) obsługuje wpis formularza. Druga Create
metoda ( HttpPost
wersja) sprawdza ModelState.IsValid
, czy film ma jakiekolwiek błędy walidacji. Pobieranie tej właściwości ocenia wszystkie atrybuty weryfikacji, które zostały zastosowane do obiektu. Jeśli obiekt zawiera błędy sprawdzania poprawności, Create
metoda redisplays formularza. Jeśli nie ma żadnych błędów, metoda zapisuje nowy film w bazie danych. W naszym przykładzie filmu formularz nie jest publikowany na serwerze po wykryciu błędów walidacji po stronie klienta; druga Create
metoda nigdy nie jest wywoływana. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta zostanie wyłączona, a metoda HTTP POST Create
sprawdzi ModelState.IsValid
, czy film zawiera jakiekolwiek błędy walidacji.
Punkt przerwania można ustawić w metodzie HttpPost Create
i sprawdzić, czy metoda nigdy nie jest wywoływana, walidacja po stronie klienta nie będzie przesyłać danych formularza po wykryciu błędów walidacji. Jeśli wyłączysz język JavaScript w przeglądarce, prześlij formularz z błędami, punkt przerwania zostanie trafiony. Nadal uzyskujesz pełną walidację bez języka JavaScript. Na poniższej ilustracji przedstawiono sposób wyłączania języka JavaScript w programie Internet Explorer.
Na poniższej ilustracji pokazano, jak wyłączyć język JavaScript w przeglądarce FireFox.
Na poniższej ilustracji przedstawiono sposób wyłączania języka JavaScript w przeglądarce Chrome.
Poniżej znajduje się szablon widoku Create.cshtml utworzony wcześniej w samouczku. Jest on używany przez metody akcji pokazane powyżej zarówno do wyświetlania formularza początkowego, jak i do ponownego redysponowania go w przypadku błędu.
@model MvcMovie.Models.Movie
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
</div>
@*Fields removed for brevity.*@
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Zwróć uwagę, że kod używa Html.EditorFor
pomocnika do wyprowadzania <input>
elementu dla każdej Movie
właściwości. Obok tego pomocnika jest wywołanie metody pomocniczej Html.ValidationMessageFor
. Te dwie metody pomocnicze działają z obiektem modelu przekazywanym przez kontroler do widoku (w tym przypadku obiektem Movie
). Automatycznie wyszukują atrybuty weryfikacji określone w modelu i wyświetlają odpowiednio komunikaty o błędach.
Naprawdę miło jest to, że ani kontroler, ani Create
szablon widoku nie wie nic o rzeczywistych regułach walidacji, które są wymuszane, ani o wyświetlanych konkretnych komunikatach o błędach. Reguły walidacji i ciągi błędów są określone tylko w Movie
klasie. Te same reguły sprawdzania poprawności są automatycznie stosowane do Edit
widoku i wszystkich innych szablonów widoków, które można utworzyć, aby edytować model.
Jeśli chcesz później zmienić logikę weryfikacji, możesz to zrobić w dokładnie jednym miejscu, dodając atrybuty weryfikacji do modelu (w tym przykładzie movie
klasa). Nie trzeba martwić się o niespójność różnych części aplikacji ze sposobem wymuszania reguł — cała logika walidacji zostanie zdefiniowana w jednym miejscu i używana wszędzie. Dzięki temu kod jest bardzo czysty i ułatwia konserwację i rozwijanie. Oznacza to, że będziesz w pełni przestrzegać zasady DRY .
Używanie atrybutów Typu danych
Otwórz plik Movie.cs i sprawdź klasęMovie
. System.ComponentModel.DataAnnotations
Przestrzeń nazw udostępnia atrybuty formatowania oprócz wbudowanego zestawu atrybutów weryfikacji. Zastosowaliśmy DataType
już wartość wyliczenia do daty wydania i pól ceny. Poniższy kod przedstawia ReleaseDate
właściwości i Price
z odpowiednim DataType
atrybutem.
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
Atrybuty DataType udostępniają tylko wskazówki dotyczące aparatu wyświetlania w celu formatowania danych (i podawania atrybutów, takich jak <a>
adres URL i <a href="mailto:EmailAddress.com">
adres e-mail). Możesz użyć atrybutu RegularExpression , aby zweryfikować format danych. Atrybut DataType służy do określania typu danych, który jest bardziej szczegółowy niż typ wewnętrzny bazy danych, nie są atrybutami walidacji. W tym przypadku chcemy śledzić tylko datę, a nie datę i godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Numer telefonu, Waluta, Adres e-mail i inne. Atrybut DataType
może również umożliwić aplikacji automatyczne udostępnianie funkcji specyficznych dla typu. Na przykład mailto:
można utworzyć link dla elementu DataType.EmailAddress, a selektor dat można podać dla elementu DataType.Date w przeglądarkach, które obsługują kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataType nie zapewniają żadnej walidacji.
DataType.Date
nie określa formatu wyświetlanej daty. Domyślnie pole danych jest wyświetlane zgodnie z domyślnymi formatami na podstawie informacji o kulturze serwera.
Atrybut DisplayFormat
jest używany do jawnego określenia formatu daty:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
Ustawienie ApplyFormatInEditMode
określa, że określone formatowanie powinno być również stosowane, gdy wartość jest wyświetlana w polu tekstowym do edycji. (Możesz nie chcieć tego dla niektórych pól — na przykład w przypadku wartości walutowych symbol waluty w polu tekstowym do edycji).
Atrybut DisplayFormat można użyć samodzielnie, ale zazwyczaj warto użyć atrybutu DataType. Atrybut DataType
przekazuje semantyka danych w przeciwieństwie do sposobu renderowania ich na ekranie i zapewnia następujące korzyści, których nie otrzymujesz za pomocą DisplayFormat
polecenia :
- Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlenia kontrolki kalendarza, symbolu waluty odpowiedniego dla ustawień regionalnych, linków poczty e-mail itp.).
- Domyślnie przeglądarka będzie renderować dane przy użyciu poprawnego formatu na podstawie ustawień regionalnych.
- Atrybut DataType może umożliwić MVC wybranie odpowiedniego szablonu pola do renderowania danych ( DisplayFormat , jeśli jest używany przez siebie przy użyciu szablonu ciągu). Aby uzyskać więcej informacji, zobacz szablony ASP.NET MVC 2 Brada Wilsona. (Chociaż został napisany dla MVC 2, ten artykuł nadal dotyczy bieżącej wersji ASP.NET MVC).
Jeśli używasz atrybutu DataType
z polem daty, musisz również określić DisplayFormat
atrybut, aby upewnić się, że pole jest poprawnie renderowane w przeglądarkach Chrome. Aby uzyskać więcej informacji, zobacz ten wątek StackOverflow.
Uwaga
Sprawdzanie poprawności zapytania jQuery nie działa z atrybutem Range i DateTime. Na przykład następujący kod zawsze wyświetla błąd weryfikacji po stronie klienta, nawet jeśli data znajduje się w określonym zakresie:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Aby użyć atrybutu Range z funkcją DateTime, należy wyłączyć walidację daty zapytania jQuery. Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania twardych dat w modelach, więc użycie atrybutu Range i daty/godziny jest zniechęcane.
Poniższy kod przedstawia łączenie atrybutów w jednym wierszu:
public class Movie
{
public int ID { get; set; }
[Required,StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"),DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
[Range(1, 100),DataType(DataType.Currency)]
public decimal Price { get; set; }
[Required,StringLength(5)]
public string Rating { get; set; }
}
W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w zakresie automatycznie generowanych Details
metod i Delete
.