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 użyto ASP.NET Core MVC, co zapewnia wiele ulepszeń w tym samouczku.

W tym samouczku przedstawiono ASP.NET Core MVC z kontrolerami i widokami. Razor Pages to nowa alternatywa w ASP.NET Core, oparty na stronach model programowania, który ułatwia tworzenie internetowego interfejsu użytkownika i bardziej wydajne. Zalecamy wypróbowanie samouczka Razor Pages przed wersją MVC. Samouczek usługi 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 weryfikacji są wymuszane za każdym razem, gdy użytkownik próbuje utworzyć lub edytować film przy użyciu aplikacji.

Utrzymywanie suchych rzeczy

Jeden z podstawowych zestawów projektowych ASP.NET MVC to DRY ("Nie powtarzaj siebie"). ASP.NET MVC zachęca do określania funkcjonalności lub zachowania tylko raz, a następnie ich odzwierciedlenia wszędzie w aplikacji. Zmniejsza to ilość kodu potrzebnego do pisania i sprawia, że kod jest mniej podatny na błędy i ułatwia konserwację.

Obsługa walidacji zapewniana przez ASP.NET MVC i Entity Framework Code First to doskonały przykład akcji zasady DRY. Reguły weryfikacji 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 walidacji w aplikacji filmowej.

Dodawanie reguł walidacji do modelu filmowego

Zaczniesz od dodania logiki weryfikacji do Movie klasy.

Otwórz plik Movie.cs . Zwróć uwagę, że System.ComponentModel.DataAnnotations przestrzeń nazw nie zawiera System.Webelementu . Funkcja DataAnnotations udostępnia wbudowany zestaw atrybutów weryfikacji, które można deklaratywnie zastosować do dowolnej klasy lub właściwości. (Zawiera również atrybuty formatowania, takie jak DataType , które ułatwiają formatowanie i nie zapewniają żadnej weryfikacji).

Teraz zaktualizuj klasęMovie, aby skorzystać z wbudowanych Requiredatrybutów , StringLength, RegularExpression i Range walidacji. Zastąp klasę Movie następującymi elementami:

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 pozycję Otwórz definicję tabeli:

Zrzut ekranu przedstawiający otwarte okno Eksploratora serwera i na karcie d b o dot Movies Design (Projektowanie filmów).

Na powyższym obrazie widać, że wszystkie pola ciągu są ustawione na NVARCHAR (MAX). Użyjemy migracji do zaktualizowania schematu. Skompiluj rozwiązanie, a następnie otwórz okno Konsola menedżera pakietów i wprowadź następujące polecenia:

add-migration DataAnnotations
update-database

Po zakończeniu tego polecenia program Visual Studio otworzy 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ż możliwe do wartości null (oznacza to, że należy wprowadzić wartość). Pole Rating ma maksymalną długość 5 i Title ma maksymalną długość 60. Minimalna długość 3 na i Title zakres nie Price utworzył zmian schematu.

Sprawdź schemat filmu:

Zrzut ekranu przedstawiający kartę d b o dot Movies Design (Projektowanie filmów). Tytuł i ocena są zaewidencjonowane w kolumnie Zezwalaj na wartości null.

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. Atrybuty Required i MinimumLength wskazują, że właściwość musi mieć wartość, ale nic nie uniemożliwia użytkownikowi wprowadzenia 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 GenreRating kodzie należy 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 jej 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ł weryfikacji przez .NET Framework pomaga zwiększyć niezawodność aplikacji. Gwarantuje to również, że nie można zapomnieć o zweryfikowaniu czegoś i przypadkowo zezwolić na nieprawidłowe dane 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.

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ć globalizowanie NuGet zgodnie z opisem wcześniej w tym samouczku.

Zwróć uwagę, że formularz automatycznie używał koloru czerwonego 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 zarówno po stronie klienta (przy użyciu języka JavaScript i jQuery) jak i po stronie serwera (w przypadku wyłączenia języka JavaScript przez użytkownika).

Prawdziwą 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 odebrały reguły sprawdzania poprawności 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 występuje walidacja w metodzie Create View and Create Action

Możesz się zastanawiać, w jaki sposób 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 Create. 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 ma błędy walidacji, 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, gdy występują błędy weryfikacji wykryte po stronie klienta; drugaCreatemetoda 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 ma jakiekolwiek błędy weryfikacji.

Można 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 weryfikacji. 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 pokazano, jak wyłączyć język JavaScript w programie Internet Explorer.

Zrzut ekranu przedstawiający otwarte okno Opcje internetowe i na karcie Zabezpieczenia. Okno Poziom niestandardowy jest otwarte, a aktywne wykonywanie skryptów jest wyłączone.

Zrzut ekranu przedstawiający wpis H t p i 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. Zawartość jest zaznaczona i opcja Włącz skrypt Java jest zakreślina na czerwono.

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

Zrzut ekranu przedstawiający ustawienie skryptu Java i opcję zezwalania lub wyłączania.

Poniżej znajduje się szablon widoku Create.cshtml , który został utworzony wcześniej w samouczku. Jest on używany przez metody akcji pokazane powyżej, aby wyświetlić formularz początkowy i odtworzyć 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ę, jak kod używa Html.EditorFor pomocnika do wyprowadzania <input> elementu dla każdej Movie właściwości. Obok tego pomocnika jest wywołanie Html.ValidationMessageFor metody pomocnika. 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, co naprawdę jest miłe w tym podejściu, to to, że ani kontroler, ani Create szablon widoku nic nie wie o rzeczywistych regułach weryfikacji, które są wymuszane, lub 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 wszelkich 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ł — wszystkie logiki weryfikacji będą definiowane w jednym miejscu i używane wszędzie. Dzięki temu kod jest bardzo czysty i ułatwia konserwację i rozwijanie. Oznacza to, że będziesz w pełni honorować zasadę 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. Do daty wydania i pól cen zastosowaliśmy DataType już wartość wyliczenia. 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 zawierają tylko wskazówki dla aparatu wyświetlania, aby sformatować dane (i podać 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 specyficzny niż typ wewnętrzny bazy danych, nie są atrybutami weryfikacji. W tym przypadku chcemy śledzić tylko datę, a nie datę i godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Liczba telefonów, 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 mogą zrozumieć przeglądarki HTML 5. Atrybuty DataType nie zapewniają żadnej weryfikacji.

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 tego nie chcieć w przypadku niektórych pól — na przykład w przypadku wartości waluty możesz nie chcieć symbolu waluty w polu tekstowym do edycji).

Atrybut DisplayFormat można użyć sam w sobie, 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 DisplayFormatpomocą 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 renderuje dane przy użyciu poprawnego formatu na podstawie ustawień regionalnych.
  • Atrybut DataType może umożliwić MVC wybranie odpowiedniego szablonu pola do renderowania danych ( format 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 w trybie jQuery nie działa z atrybutem Zakres i datą/godziną. Na przykład poniższy 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 wartością DateTime, należy wyłączyć walidację daty jQuery. Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania dat twardych w modelach, dlatego nie zaleca się używania atrybutu Range i daty/godziny .

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 automatycznie wygenerowane Details i Delete metody.