Część 9. Dodawanie walidacji do aplikacji MVC platformy ASP.NET Core

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Autor: Rick Anderson

W tej sekcji:

  • Logika walidacji jest dodawana do Movie modelu.
  • Upewnij się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik tworzy lub edytuje film.

Utrzymywanie suchych elementów

Jednym z zestawów projektu MVC jest DRY ("Nie powtarzaj siebie"). ASP.NET Core 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, ułatwia testowanie i ułatwia konserwację.

Obsługa walidacji zapewniana przez MVC i Entity Framework Core Code First jest dobrym 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.

Dodawanie reguł walidacji do modelu filmu

Przestrzeń nazw DataAnnotations udostępnia zestaw wbudowanych atrybutów weryfikacji, które są stosowane deklaratywnie do klasy lub właściwości. Przestrzeń nazw DataAnnotations zawiera również atrybuty formatowania, takie jak DataType, które pomagają w formatowaniu i nie zapewniają żadnej walidacji.

Zaktualizuj klasęMovie, aby korzystać z wbudowanych atrybutów Requiredweryfikacji , StringLength, RegularExpressionRange i DataType atrybutu formatowania.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Atrybuty weryfikacji określają zachowanie, które chcesz wymusić na właściwościach 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 jako dane wejściowe. W poprzednim kodzie w polu „Genre” (Gatunek):

    • Muszą być używane tylko litery.
    • Pierwsza litera musi być wielką literą. Białe spacje są dozwolone, gdy liczby i znaki specjalne są niedozwolone.
  • W atrybucie RegularExpression „Rating” (Klasyfikacja):

    • Pierwszy znak musi być wielką literą.
    • Kolejne znaki mogą być znakami specjalnymi i cyframi. W atrybucie Rating wartość „PG-13” jest prawidłowa, ale w przypadku atrybutu Genre — nie.
  • 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].

Automatyczne wymuszanie reguł weryfikacji przez platformę ASP.NET Core 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

Uruchom aplikację i przejdź do kontrolera Filmy.

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

Formularz widoku filmu z wieloma błędami weryfikacji po stronie klienta jQuery

Uwaga

Może nie być możliwe wprowadzenie przecinków dziesiętnych w polach dziesiętnych. Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla przecinka dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten komentarz usługi GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Zwróć uwagę, że formularz automatycznie renderował odpowiedni komunikat o błędzie weryfikacji w każdym polu zawierającym nieprawidłową wartość. 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).

Ważną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController klasie lub w Create.cshtml widoku, aby włączyć ten interfejs 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ędzia programistyczne F12.

Jak działa walidacja

Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Poniższy kod przedstawia dwie Create metody.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(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 formularz nie jest publikowany na serwerze, gdy występują błędy walidacji wykryte po stronie klienta; druga Create metoda nigdy nie jest wywoływana, gdy występują błędy weryfikacji po stronie klienta. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta jest wyłączona i możesz przetestować metodę ModelState.IsValid HTTP POSTCreate, wykrywając błędy walidacji.

Możesz ustawić punkt przerwania 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 przeglądarce Firefox.

Firefox: na karcie Zawartość w obszarze Opcje usuń zaznaczenie pola wyboru Włącz język Javascript.

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

Google Chrome: w sekcji Javascript ustawień zawartości wybierz pozycję Nie zezwalaj żadnej witrynie na uruchamianie języka JavaScript.

Po wyłączeniu języka JavaScript opublikuj nieprawidłowe dane i przejdź przez debuger.

Podczas debugowania wpisu nieprawidłowych danych funkcja Intellisense w kolumnie ModelState.IsValid pokazuje, że wartość jest fałsz.

Część szablonu Create.cshtml widoku jest wyświetlana w następującym znaczniku:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

Powyższy znacznik jest używany przez metody akcji do wyświetlania początkowego formularza i ponownego redysponowania go w przypadku błędu.

Pomocnik tagów wejściowych używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta. Pomocnik tagu weryfikacji wyświetla błędy walidacji. Aby uzyskać więcej informacji, zobacz Walidacja .

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 musisz 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

Movie.cs Otwórz plik 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.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Atrybuty DataType zawierają tylko wskazówki dla aparatu wyświetlania, aby sformatować dane i dostarczyć elementy/atrybuty, takie 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 godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Telefon Number, 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 DataType.EmailAddresselementu , a selektor dat można udostępnić DataType.Date w przeglądarkach obsługujących kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataTypenie 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 serwera CultureInfo.

Atrybut DisplayFormat jest używany do jawnego określenia formatu daty:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Ustawienie ApplyFormatInEditMode określa, że 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 prawdopodobnie nie chcesz, aby symbol waluty w polu tekstowym był edytowany).

Atrybut można użyć DisplayFormat samodzielnie, ale zazwyczaj dobrym pomysłem jest użycie atrybutu DataType . Atrybut DataType przekazuje semantyka danych, w przeciwieństwie do sposobu renderowania ich na ekranie, i zapewnia następujące korzyści, które nie są uzyskiwane za pomocą elementu DisplayFormat:

  • Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlania 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 w celu renderowania danych ( DisplayFormat jeśli jest używany przez siebie przy użyciu szablonu ciągu).

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 z atrybutem , należy wyłączyć walidację Range daty zapytania jQuery.DateTime Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania dat twardych w modelach, dlatego użycie atrybutu Range i DateTime jest zniechęcane.

Poniższy kod przedstawia łączenie atrybutów w jednym wierszu:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w automatycznie wygenerowanych Details metodach i Delete .

Dodatkowe zasoby

W tej sekcji:

  • Logika walidacji jest dodawana do Movie modelu.
  • Upewnij się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik tworzy lub edytuje film.

Utrzymywanie suchych elementów

Jednym z zestawów projektu MVC jest DRY ("Nie powtarzaj siebie"). ASP.NET Core 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, ułatwia testowanie i ułatwia konserwację.

Obsługa walidacji zapewniana przez MVC i Entity Framework Core Code First jest dobrym 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.

Dodawanie reguł walidacji do modelu filmu

Przestrzeń nazw DataAnnotations udostępnia zestaw wbudowanych atrybutów weryfikacji, które są stosowane deklaratywnie do klasy lub właściwości. Przestrzeń nazw DataAnnotations zawiera również atrybuty formatowania, takie jak DataType, które pomagają w formatowaniu i nie zapewniają żadnej walidacji.

Zaktualizuj klasęMovie, aby korzystać z wbudowanych atrybutów Requiredweryfikacji , StringLength, RegularExpressionRange i DataType atrybutu formatowania.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Atrybuty weryfikacji określają zachowanie, które chcesz wymusić na właściwościach 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 jako dane wejściowe. W poprzednim kodzie w polu „Genre” (Gatunek):

    • Muszą być używane tylko litery.
    • Pierwsza litera musi być wielką literą. Białe spacje są dozwolone, gdy liczby i znaki specjalne są niedozwolone.
  • W atrybucie RegularExpression „Rating” (Klasyfikacja):

    • Pierwszy znak musi być wielką literą.
    • Kolejne znaki mogą być znakami specjalnymi i cyframi. W atrybucie Rating wartość „PG-13” jest prawidłowa, ale w przypadku atrybutu Genre — nie.
  • 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].

Automatyczne wymuszanie reguł weryfikacji przez platformę ASP.NET Core 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

Uruchom aplikację i przejdź do kontrolera Filmy.

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

Formularz widoku filmu z wieloma błędami weryfikacji po stronie klienta jQuery

Uwaga

Może nie być możliwe wprowadzenie przecinków dziesiętnych w polach dziesiętnych. Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla przecinka dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten komentarz usługi GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Zwróć uwagę, że formularz automatycznie renderował odpowiedni komunikat o błędzie weryfikacji w każdym polu zawierającym nieprawidłową wartość. 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).

Ważną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController klasie lub w Create.cshtml widoku, aby włączyć ten interfejs 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ędzia programistyczne F12.

Jak działa walidacja

Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Poniższy kod przedstawia dwie Create metody.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(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 formularz nie jest publikowany na serwerze, gdy występują błędy walidacji wykryte po stronie klienta; druga Create metoda nigdy nie jest wywoływana, gdy występują błędy weryfikacji po stronie klienta. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta jest wyłączona i możesz przetestować metodę ModelState.IsValid HTTP POSTCreate, wykrywając błędy walidacji.

Możesz ustawić punkt przerwania 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 przeglądarce Firefox.

Firefox: na karcie Zawartość w obszarze Opcje usuń zaznaczenie pola wyboru Włącz język Javascript.

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

Google Chrome: w sekcji Javascript ustawień zawartości wybierz pozycję Nie zezwalaj żadnej witrynie na uruchamianie języka JavaScript.

Po wyłączeniu języka JavaScript opublikuj nieprawidłowe dane i przejdź przez debuger.

Podczas debugowania wpisu nieprawidłowych danych funkcja Intellisense w kolumnie ModelState.IsValid pokazuje, że wartość jest fałsz.

Część szablonu Create.cshtml widoku jest wyświetlana w następującym znaczniku:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

Powyższy znacznik jest używany przez metody akcji do wyświetlania początkowego formularza i ponownego redysponowania go w przypadku błędu.

Pomocnik tagów wejściowych używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta. Pomocnik tagu weryfikacji wyświetla błędy walidacji. Aby uzyskać więcej informacji, zobacz Walidacja .

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 musisz 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

Movie.cs Otwórz plik 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.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Atrybuty DataType zawierają tylko wskazówki dla aparatu wyświetlania, aby sformatować dane i dostarczyć elementy/atrybuty, takie 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 godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Telefon Number, 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 DataType.EmailAddresselementu , a selektor dat można udostępnić DataType.Date w przeglądarkach obsługujących kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataTypenie 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 serwera CultureInfo.

Atrybut DisplayFormat jest używany do jawnego określenia formatu daty:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Ustawienie ApplyFormatInEditMode określa, że 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 prawdopodobnie nie chcesz, aby symbol waluty w polu tekstowym był edytowany).

Atrybut można użyć DisplayFormat samodzielnie, ale zazwyczaj dobrym pomysłem jest użycie atrybutu DataType . Atrybut DataType przekazuje semantyka danych, w przeciwieństwie do sposobu renderowania ich na ekranie, i zapewnia następujące korzyści, które nie są uzyskiwane za pomocą elementu DisplayFormat:

  • Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlania 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 w celu renderowania danych ( DisplayFormat jeśli jest używany przez siebie przy użyciu szablonu ciągu).

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 z atrybutem , należy wyłączyć walidację Range daty zapytania jQuery.DateTime Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania dat twardych w modelach, dlatego użycie atrybutu Range i DateTime jest zniechęcane.

Poniższy kod przedstawia łączenie atrybutów w jednym wierszu:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w automatycznie wygenerowanych Details metodach i Delete .

Dodatkowe zasoby

W tej sekcji:

  • Logika walidacji jest dodawana do Movie modelu.
  • Upewnij się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik tworzy lub edytuje film.

Utrzymywanie suchych elementów

Jednym z zestawów projektu MVC jest DRY ("Nie powtarzaj siebie"). ASP.NET Core 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, ułatwia testowanie i ułatwia konserwację.

Obsługa walidacji zapewniana przez MVC i Entity Framework Core Code First jest dobrym 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.

Dodawanie reguł walidacji do modelu filmu

Przestrzeń nazw DataAnnotations udostępnia zestaw wbudowanych atrybutów weryfikacji, które są stosowane deklaratywnie do klasy lub właściwości. Przestrzeń nazw DataAnnotations zawiera również atrybuty formatowania, takie jak DataType, które pomagają w formatowaniu i nie zapewniają żadnej walidacji.

Zaktualizuj klasę Movie , aby korzystać z wbudowanych Requiredatrybutów , StringLength, RegularExpressioni Range walidacji.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string? Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string? Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string? Rating { get; set; }
    }
}

Atrybuty weryfikacji określają zachowanie, które chcesz wymusić na właściwościach 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 jako dane wejściowe. W poprzednim kodzie w polu „Genre” (Gatunek):

    • Muszą być używane tylko litery.
    • Pierwsza litera musi być wielką literą. Białe spacje są dozwolone, gdy liczby i znaki specjalne są niedozwolone.
  • W atrybucie RegularExpression „Rating” (Klasyfikacja):

    • Pierwszy znak musi być wielką literą.
    • Kolejne znaki mogą być znakami specjalnymi i cyframi. W atrybucie Rating wartość „PG-13” jest prawidłowa, ale w przypadku atrybutu Genre — nie.
  • 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].

Automatyczne wymuszanie reguł weryfikacji przez platformę ASP.NET Core 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

Uruchom aplikację i przejdź do kontrolera Filmy.

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

Formularz widoku filmu z wieloma błędami weryfikacji po stronie klienta jQuery

Uwaga

Może nie być możliwe wprowadzenie przecinków dziesiętnych w polach dziesiętnych. Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla przecinka dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten komentarz usługi GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Zwróć uwagę, że formularz automatycznie renderował odpowiedni komunikat o błędzie weryfikacji w każdym polu zawierającym nieprawidłową wartość. 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).

Ważną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController klasie lub w Create.cshtml widoku, aby włączyć ten interfejs 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ędzia programistyczne F12.

Jak działa walidacja

Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Poniższy kod przedstawia dwie Create metody.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(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 formularz nie jest publikowany na serwerze, gdy występują błędy walidacji wykryte po stronie klienta; druga Create metoda nigdy nie jest wywoływana, gdy występują błędy weryfikacji po stronie klienta. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta jest wyłączona i możesz przetestować metodę ModelState.IsValid HTTP POSTCreate, wykrywając błędy walidacji.

Możesz ustawić punkt przerwania 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 przeglądarce Firefox.

Firefox: na karcie Zawartość w obszarze Opcje usuń zaznaczenie pola wyboru Włącz język Javascript.

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

Google Chrome: w sekcji Javascript ustawień zawartości wybierz pozycję Nie zezwalaj żadnej witrynie na uruchamianie języka JavaScript.

Po wyłączeniu języka JavaScript opublikuj nieprawidłowe dane i przejdź przez debuger.

Podczas debugowania wpisu nieprawidłowych danych funkcja Intellisense w kolumnie ModelState.IsValid pokazuje, że wartość jest fałsz.

Część szablonu Create.cshtml widoku jest wyświetlana w następującym znaczniku:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

Powyższy znacznik jest używany przez metody akcji do wyświetlania początkowego formularza i ponownego redysponowania go w przypadku błędu.

Pomocnik tagów wejściowych używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta. Pomocnik tagu weryfikacji wyświetla błędy walidacji. Aby uzyskać więcej informacji, zobacz Walidacja .

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 musisz 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

Movie.cs Otwórz plik 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.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }

Atrybuty DataType zawierają tylko wskazówki dla aparatu wyświetlania, aby sformatować dane i dostarczyć elementy/atrybuty, takie 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 godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Telefon Number, 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 DataType.EmailAddresselementu , a selektor dat można udostępnić DataType.Date w przeglądarkach obsługujących kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataTypenie 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 serwera CultureInfo.

Atrybut DisplayFormat jest używany do jawnego określenia formatu daty:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Ustawienie ApplyFormatInEditMode określa, że 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 prawdopodobnie nie chcesz, aby symbol waluty w polu tekstowym był edytowany).

Atrybut można użyć DisplayFormat samodzielnie, ale zazwyczaj dobrym pomysłem jest użycie atrybutu DataType . Atrybut DataType przekazuje semantyka danych, w przeciwieństwie do sposobu renderowania ich na ekranie, i zapewnia następujące korzyści, które nie są uzyskiwane za pomocą elementu DisplayFormat:

  • Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlania 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 w celu renderowania danych ( DisplayFormat jeśli jest używany przez siebie przy użyciu szablonu ciągu).

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 z atrybutem , należy wyłączyć walidację Range daty zapytania jQuery.DateTime Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania dat twardych w modelach, dlatego użycie atrybutu Range i DateTime jest zniechęcane.

Poniższy kod przedstawia łączenie atrybutów w jednym wierszu:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        public string Title { get; set; }

        [Display(Name = "Release Date"), DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
        public string Genre { get; set; }

        [Range(1, 100), DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
        public string Rating { get; set; }
    }
}

W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w automatycznie wygenerowanych Details metodach i Delete .

Dodatkowe zasoby

W tej sekcji:

  • Logika walidacji jest dodawana do Movie modelu.
  • Upewnij się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik tworzy lub edytuje film.

Utrzymywanie suchych elementów

Jednym z zestawów projektu MVC jest DRY ("Nie powtarzaj siebie"). ASP.NET Core 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, ułatwia testowanie i ułatwia konserwację.

Obsługa walidacji zapewniana przez MVC i Entity Framework Core Code First jest dobrym 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.

Dodawanie reguł walidacji do modelu filmu

Przestrzeń nazw DataAnnotations udostępnia zestaw wbudowanych atrybutów weryfikacji, które są stosowane deklaratywnie do klasy lub właściwości. Przestrzeń nazw DataAnnotations zawiera również atrybuty formatowania, takie jak DataType, które pomagają w formatowaniu i nie zapewniają żadnej walidacji.

Zaktualizuj klasę Movie , aby korzystać z wbudowanych Requiredatrybutów , StringLength, RegularExpressioni Range walidacji.

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

Atrybuty weryfikacji określają zachowanie, które chcesz wymusić na właściwościach 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 jako dane wejściowe. W poprzednim kodzie w polu „Genre” (Gatunek):

    • Muszą być używane tylko litery.
    • Pierwsza litera musi być wielką literą. Dozwolone są białe spacje, a liczby i znaki specjalne nie są dozwolone.
  • W atrybucie RegularExpression „Rating” (Klasyfikacja):

    • Pierwszy znak musi być wielką literą.
    • Kolejne znaki mogą być znakami specjalnymi i cyframi. W atrybucie Rating wartość „PG-13” jest prawidłowa, ale w przypadku atrybutu Genre — nie.
  • 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].

Automatyczne wymuszanie reguł weryfikacji przez platformę ASP.NET Core 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

Uruchom aplikację i przejdź do kontrolera Filmy.

Naciśnij 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.

Formularz widoku filmu z wieloma błędami weryfikacji po stronie klienta jQuery

Uwaga

Może nie być możliwe wprowadzenie przecinków dziesiętnych w polach dziesiętnych. Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla przecinka dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten komentarz usługi GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Zwróć uwagę, że formularz automatycznie renderował odpowiedni komunikat o błędzie weryfikacji w każdym polu zawierającym nieprawidłową wartość. 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).

Ważną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController klasie lub w Create.cshtml widoku, aby włączyć ten interfejs 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ędzia programistyczne F12.

Jak działa walidacja

Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Poniższy kod przedstawia dwie Create metody.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        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 formularz nie jest publikowany na serwerze, gdy występują błędy walidacji wykryte po stronie klienta; druga Create metoda nigdy nie jest wywoływana, gdy występują błędy weryfikacji po stronie klienta. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta jest wyłączona i możesz przetestować metodę ModelState.IsValid HTTP POSTCreate, wykrywając błędy walidacji.

Możesz ustawić punkt przerwania 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 przeglądarce Firefox.

Firefox: na karcie Zawartość w obszarze Opcje usuń zaznaczenie pola wyboru Włącz język Javascript.

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

Google Chrome: w sekcji Javascript ustawień zawartości wybierz pozycję Nie zezwalaj żadnej witrynie na uruchamianie języka JavaScript.

Po wyłączeniu języka JavaScript opublikuj nieprawidłowe dane i przejdź przez debuger.

Podczas debugowania wpisu nieprawidłowych danych funkcja Intellisense w kolumnie ModelState.IsValid pokazuje, że wartość jest fałsz.

Część szablonu Create.cshtml widoku jest wyświetlana w następującym znaczniku:


<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>           
       
        @*Markup removed for brevity.*@

Powyższy znacznik jest używany przez metody akcji do wyświetlania początkowego formularza i ponownego redysponowania go w przypadku błędu.

Pomocnik tagów wejściowych używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta. Pomocnik tagu weryfikacji wyświetla błędy walidacji. Aby uzyskać więcej informacji, zobacz Walidacja .

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 musisz 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

Movie.cs Otwórz plik 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.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

Atrybuty DataType zawierają tylko wskazówki dla aparatu wyświetlania w celu formatowania danych (i dostarcza elementy/atrybuty, takie 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 godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Telefon Number, 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 DataType.EmailAddresselementu , a selektor dat można udostępnić DataType.Date w przeglądarkach obsługujących kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataTypenie 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 serwera CultureInfo.

Atrybut DisplayFormat jest używany do jawnego określenia formatu daty:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Ustawienie ApplyFormatInEditMode określa, że 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 prawdopodobnie nie chcesz, aby symbol waluty w polu tekstowym był edytowany).

Atrybut można użyć DisplayFormat samodzielnie, ale zazwyczaj dobrym pomysłem jest użycie atrybutu DataType . Atrybut DataType przekazuje semantyka danych, w przeciwieństwie do sposobu renderowania ich na ekranie, i zapewnia następujące korzyści, które nie są uzyskiwane za pomocą elementu DisplayFormat:

  • Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlania 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 w celu renderowania danych ( DisplayFormat jeśli jest używany przez siebie przy użyciu szablonu ciągu).

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 z atrybutem , należy wyłączyć walidację Range daty zapytania jQuery.DateTime Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania dat twardych w modelach, dlatego użycie atrybutu Range i DateTime jest zniechęcane.

Poniższy kod przedstawia łączenie atrybutów w jednym wierszu:

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }

    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

W następnej części serii przejrzymy aplikację i wprowadzimy pewne ulepszenia w automatycznie wygenerowanych Details metodach i Delete .

Dodatkowe zasoby