Dodawanie logiki walidacji do modelu filmu
Autor: Rick Anderson
Uwaga
Zaktualizowana wersja tego samouczka jest dostępna tutaj , która używa ASP.NET MVC 5 i Visual Studio 2013. Jest bezpieczniejszy, znacznie prostszy do naśladowania i demonstruje więcej funkcji.
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. Dodaj instrukcję using
w górnej części pliku, który odwołuje się do System.ComponentModel.DataAnnotations
przestrzeni nazw:
using System.ComponentModel.DataAnnotations;
Zwróć uwagę, że 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.
Teraz zaktualizuj klasę Movie
, aby korzystać z wbudowanych Required
atrybutów , StringLength
i Range
walidacji. Użyj następującego kodu jako przykładu, gdzie należy zastosować atrybuty.
public class Movie {
public int ID { get; set; }
[Required]
public string Title { get; set; }
[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; }
[StringLength(5)]
public string Rating { get; set; }
}
Uruchom aplikację i ponownie zostanie wyświetlony następujący błąd czasu wykonywania:
Model tworzący kopię zapasową kontekstu "MovieDBContext" zmienił się od czasu utworzenia bazy danych. Rozważ użycie Migracje Code First do zaktualizowania bazy danych (https://go.microsoft.com/fwlink/?LinkId=238269).
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 AddDataAnnotationsMig
update-database
Po zakończeniu tego polecenia program Visual Studio otwiera plik klasy definiujący nową DbMigration
klasę pochodną o określonej nazwie (AddDataAnnotationsMig), a w Up
metodzie można zobaczyć kod, który aktualizuje ograniczenia schematu. Pola Title
i Genre
nie są już dopuszczane do wartości null (czyli musisz wprowadzić wartość), a Rating
pole ma maksymalną długość 5.
Atrybuty weryfikacji określają zachowanie, do którego mają być wymuszane właściwości modelu, do których są stosowane. Atrybut Required
wskazuje, że właściwość musi mieć wartość. W tym przykładzie film musi mieć wartości właściwości Title
, , ReleaseDate
Genre
iPrice
, aby być prawidłowe. 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 wewnętrzne (takie jak decimal, int, float, DateTime
) są domyślnie 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 podczas wywoływanej SaveChanges
metody, ponieważ brakuje kilku wymaganych Movie
wartości właściwości, a cena jest równa zero (która jest wyjątkiem prawidłowego zakresu).
MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
movie.Price = 0.0M;
db.Movies.Add(movie);
db.SaveChanges(); // <= Will throw server side validation exception
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.
Oto kompletna lista kodu dla zaktualizowanego pliku Movie.cs :
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace MvcMovie.Models {
public class Movie {
public int ID { get; set; }
[Required]
public string Title { get; set; }
[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; }
[StringLength(5)]
public string Rating { get; set; }
}
public class MovieDBContext : DbContext {
public DbSet<Movie> Movies { get; set; }
}
}
Interfejs użytkownika błędu walidacji w usłudze ASP.NET MVC
Uruchom ponownie aplikację i przejdź do adresu URL /Movies .
Kliknij link Utwórz nowy, aby dodać nowy film. Wypełnij formularz nieprawidłowymi wartościami, a następnie kliknij przycisk Utwórz .
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ć globalize.js i określone kultury/globalize.cultures.js file(from https://github.com/jquery/globalize ) i JavaScript do użycia .Globalize.parseFloat
Poniższy kod przedstawia modyfikacje pliku Views\Movies\Edit.cshtml do pracy z kulturą "fr-FR":
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/globalize.js"></script>
<script src="~/Scripts/globalize.culture.fr-FR.js"></script>
<script>
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$(document).ready(function () {
Globalize.culture('fr-FR');
});
</script>
<script>
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Use the Globalization plugin to parse the value
var val = $.global.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
</script>
}
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.
Być może zauważysz, że właściwości Title
i Genre
, wymagany atrybut nie jest wymuszany do momentu przesłania formularza (naciśnij przycisk Utwórz ) lub wprowadź tekst w polu wejściowym i go usunął. W przypadku pola, które początkowo jest puste (na przykład pola w widoku Tworzenia) i które ma tylko wymagany atrybut i nie ma innych atrybutów weryfikacji, możesz wykonać następujące czynności, aby wyzwolić walidację:
- Na karcie w polu.
- Wprowadź jakiś tekst.
- Na karcie.
- Wróć do pola kartą.
- Usuń tekst.
- Na karcie.
Powyższa sekwencja wyzwoli wymaganą walidację bez naciśnięcia przycisku przesyłania. Po prostu naciśnięcie przycisku przesyłania bez wprowadzania któregokolwiek z pól spowoduje wyzwolenie weryfikacji po stronie klienta. Dane formularza nie są wysyłane do serwera, dopóki nie wystąpią żadne błędy weryfikacji po stronie klienta. Można to przetestować, umieszczając punkt przerwania w metodzie HTTP Post lub za pomocą narzędzia fiddler lub narzędzi deweloperskich IE 9 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.
//
// GET: /Movies/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Movies/Create
[HttpPost]
public ActionResult Create(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 (wersja HttpPost
) wywołuje metodę ModelState.IsValid
w celu sprawdzenia, czy film ma jakiekolwiek błędy walidacji. Wywołanie tej metody ocenia wszystkie atrybuty walidacji, które zostały zastosowane do obiektu. Jeśli obiekt zawiera błędy weryfikacji, Create
metoda ponownie wyświetli formularz. Jeśli nie ma żadnych błędów, metoda zapisuje nowy film w bazie danych. W naszym przykładzie filmu, który używamy, 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 i wywołania ModelState.IsValid
metody HTTP POST Create
w celu sprawdzenia, 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 za pomocą przeglądarki 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>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ReleaseDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ReleaseDate)
@Html.ValidationMessageFor(model => model.ReleaseDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Genre)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Genre)
@Html.ValidationMessageFor(model => model.Genre)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Rating)
@Html.ValidationMessageFor(model => model.Rating)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
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.
To podejście jest naprawdę miłe, że ani kontroler, ani szablon tworzenia 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 widoku Edycji 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.
Dodawanie formatowania do modelu filmu
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 DisplayFormat
atrybutem.
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
Atrybuty DataType
nie są atrybutami walidacji, są używane do powiadamiania aparatu wyświetlania, jak renderować kod HTML. W powyższym przykładzie DataType.Date
atrybut wyświetla daty filmu tylko jako daty, bez godziny. Na przykład następujące DataType
atrybuty nie weryfikują formatu danych:
[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]
Atrybuty wymienione powyżej zawierają tylko wskazówki dotyczące aparatu wyświetlania w celu formatowania danych (i podawania atrybutów, takich jak <> adres URL i <href="mailto:EmailAddress.com"> dla wiadomości e-mail. Możesz użyć atrybutu RegularExpression , aby zweryfikować format danych.
Alternatywne podejście do używania DataType
atrybutów można jawnie ustawić DataFormatString
wartość. Poniższy kod przedstawia właściwość daty wydania z ciągiem formatu daty (a mianowicie "d"). Użyjesz tej opcji, aby określić, że nie chcesz korzystać z godziny w ramach daty wydania.
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }
Poniżej przedstawiono kompletną Movie
klasę.
public class Movie {
public int ID { get; set; }
[Required]
public string Title { get; set; }
[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; }
[StringLength(5)]
public string Rating { get; set; }
}
Uruchom aplikację i przejdź do Movies
kontrolera. Data i cena wydania są ładnie sformatowane. Na poniższej ilustracji przedstawiono datę wydania i cenę przy użyciu wartości "fr-FR" jako kultury.
Na poniższej ilustracji przedstawiono te same dane wyświetlane z kulturą domyślną (angielski stany USA).
W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w zakresie automatycznie generowanych Details
metod i Delete
.