Udostępnij za pośrednictwem


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.Webelementu . 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 Requiredatrybutów , StringLengthi 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, , ReleaseDateGenreiPrice, 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 .

8_validationErrors

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ę:

  1. Na karcie w polu.
  2. Wprowadź jakiś tekst.
  3. Na karcie.
  4. Wróć do pola kartą.
  5. Usuń tekst.
  6. 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.

Zrzut ekranu przedstawiający stronę Tworzenie filmu W JĘZYKU C W języku M. Alert obok pozycji Tytuł wskazuje, że pole Tytuł jest wymagane. Alert obok pozycji Gatunek wskazuje, że pole Gatunek jest wymagane.

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 Createmetoda 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.

Zrzut ekranu przedstawiający okno Opcje internetowe otwarte na karcie Zabezpieczenia. Poziom niestandardowy jest zakreśliny na czerwono. W oknie Ustawienia zabezpieczeń aktywne wykonywanie skryptów jest ustawione na wartość wyłączone. Pasek przewijania jest zakreśliny na czerwono.

Zrzut ekranu przedstawiający wpis H t t p. Jeśli kropka stanu modelu jest prawidłowa, jest wyróżniona.

Na poniższej ilustracji pokazano, jak wyłączyć język JavaScript w przeglądarce FireFox.

Zrzut ekranu przedstawiający okno Opcje. Zaznaczono zawartość i zaznaczono pole wyboru Włącz skrypt Java.

Na poniższej ilustracji przedstawiono sposób wyłączania języka JavaScript za pomocą przeglądarki Chrome.

Zrzut ekranu przedstawiający stronę Opcje. Pod kapturem jest zaznaczony i zakreśliny na czerwono. W obszarze Ustawienia zawartości skrypt języka Java jest ustawiony na zezwalanie wszystkim witrynom na uruchamianie skryptu Java.

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.

8_format_SM

Na poniższej ilustracji przedstawiono te same dane wyświetlane z kulturą domyślną (angielski stany USA).

Zrzut ekranu przedstawiający stronę indeksu filmów języka C języka M V z wyświetlonymi czterema filmami.

W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w zakresie automatycznie generowanych Details metod i Delete .