Udostępnij za pośrednictwem


Dodawanie walidacji

Autor: Rick Anderson

Uwaga

Zaktualizowana wersja tego samouczka jest dostępna tutaj przy użyciu najnowszej wersji programu Visual Studio. W nowym samouczku jest używany ASP.NET Core MVC, który oferuje wiele ulepszeń w tym samouczku.

W tym samouczku przedstawiono ASP.NET Core MVC z kontrolerami i widokami. Platforma Razor Pages to nowa alternatywa dla platformy ASP.NET Core— oparty na stronach model programowania, który ułatwia tworzenie internetowego interfejsu użytkownika i wydajniejsze. Zalecamy wypróbowanie samouczka razor Pages przed wersją MVC. Samouczek razor Pages:

  • Jest łatwiejsze do naśladowania.
  • Obejmuje więcej funkcji.
  • Jest preferowanym podejściem do tworzenia nowych aplikacji.

W tej sekcji dodasz logikę walidacji do Movie modelu i upewnisz się, że reguły walidacji są wymuszane za każdym razem, gdy użytkownik spróbuje utworzyć lub edytować film przy użyciu aplikacji.

Utrzymywanie suchych rzeczy

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

Obsługa walidacji zapewniana przez ASP.NET MVC i Entity Framework Code First jest doskonałym przykładem zasady DRY w działaniu. Reguły walidacji można deklaratywne określić w jednym miejscu (w klasie modelu), a reguły są wymuszane wszędzie w aplikacji.

Przyjrzyjmy się, jak można skorzystać z tej obsługi weryfikacji w aplikacji filmowej.

Dodawanie reguł walidacji do modelu filmu

Zaczniesz od dodania logiki weryfikacji do Movie klasy.

Otwórz plik Movie.cs. Zwróć uwagę, że System.ComponentModel.DataAnnotations przestrzeń nazw nie zawiera System.Webelementu . Funkcja DataAnnotations udostępnia wbudowany zestaw atrybutów weryfikacji, które można deklaratywnie stosować do dowolnej klasy lub właściwości. (Zawiera również atrybuty formatowania, takie jak Typ danych, który pomaga w formatowaniu i nie zapewnia żadnej walidacji.

Teraz zaktualizuj klasęMovie, aby korzystać z wbudowanych Requiredatrybutów , StringLengthRegularExpression i Range walidacji. Zastąp klasę Movie następującym kodem:

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

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

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
  
    [RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

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

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

Atrybut StringLength ustawia maksymalną długość ciągu i ustawia to ograniczenie w bazie danych, dlatego schemat bazy danych ulegnie zmianie. Kliknij prawym przyciskiem myszy tabelę Filmy w Eksploratorze serwera i kliknij polecenie Otwórz definicję tabeli:

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

Na powyższej ilustracji widać, że wszystkie pola ciągów są ustawione na NVARCHAR (MAX). Użyjemy migracji do zaktualizowania schematu. Skompiluj rozwiązanie, a następnie otwórz okno konsoli Menedżer pakietów i wprowadź następujące polecenia:

add-migration DataAnnotations
update-database

Po zakończeniu tego polecenia program Visual Studio otwiera plik klasy definiujący nową DbMigration klasę pochodną o określonej nazwie (DataAnnotations), a w Up metodzie można zobaczyć kod, który aktualizuje ograniczenia schematu:

public override void Up()
{
    AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
    AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
    AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
}

Pole Genre nie jest już dopuszczające wartości null (oznacza to, że musisz wprowadzić wartość). Pole Rating ma maksymalną długość 5 i Title ma maksymalną długość 60. Minimalna długość 3 w obiekcie Title i zakres nie Price utworzył zmian schematu.

Zbadaj schemat filmu:

Zrzut ekranu przedstawiający kartę d b o dot Movies Design (Projektowanie filmów). Pole Tytuł i Ocena są zaznaczone 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, do których są stosowane. Atrybuty Required i MinimumLength wskazują, że właściwość musi mieć wartość, ale nic nie uniemożliwia użytkownikowi wprowadzania białych znaków w celu spełnienia tej weryfikacji. Atrybut RegularExpression służy do ograniczania liczby znaków, które mogą być wprowadzane. W powyższym Genre kodzie należy Rating używać tylko liter (białe znaki, cyfry i znaki specjalne są niedozwolone). Atrybut Range ogranicza wartość do określonego zakresu. Atrybut StringLength umożliwia ustawienie maksymalnej długości właściwości ciągu i opcjonalnie jego minimalnej długości. Typy wartości (takie jak decimal, int, float, DateTime) są z natury wymagane i nie wymagają atrybutu Required .

Code First gwarantuje, że reguły weryfikacji określone w klasie modelu są wymuszane przed zapisaniem zmian w bazie danych przez aplikację. Na przykład poniższy kod zgłosi wyjątek DbEntityValidationException po SaveChanges wywołaniu metody, ponieważ brakuje kilku wymaganych Movie wartości właściwości:

MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
db.Movies.Add(movie);
db.SaveChanges();        // <= Will throw server side validation exception

Powyższy kod zgłasza następujący wyjątek:

Walidacja nie powiodła się dla co najmniej jednej jednostki. Aby uzyskać więcej informacji, zobacz właściwość EntityValidationErrors.

Automatyczne wymuszanie reguł walidacji przez program .NET Framework pomaga zwiększyć niezawodność aplikacji. Gwarantuje to również, że nie można zapomnieć o zweryfikowaniu czegoś i przypadkowo niech złych danych w bazie danych.

Interfejs użytkownika błędu walidacji w usłudze ASP.NET MVC

Uruchom aplikację i przejdź do adresu URL /Movies .

Kliknij link Utwórz nowy, aby dodać nowy film. Wypełnij formularz kilkoma nieprawidłowymi wartościami. Gdy tylko walidacja po stronie klienta jQuery wykryje błąd, zostanie wyświetlony komunikat o błędzie.

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żył czerwonego koloru obramowania w celu wyróżnienia pól tekstowych zawierających nieprawidłowe dane i emitował odpowiedni komunikat o błędzie walidacji obok każdego z nich. Błędy są wymuszane po stronie klienta (przy użyciu języków JavaScript i jQuery) i po stronie serwera (w przypadku wyłączenia języka JavaScript przez użytkownika).

Realną korzyścią jest to, że nie trzeba zmieniać pojedynczego wiersza kodu w MoviesController klasie ani w widoku Create.cshtml w celu włączenia tego interfejsu użytkownika weryfikacji. Kontroler i widoki utworzone wcześniej w tym samouczku automatycznie podniosły reguły weryfikacji określone przy użyciu atrybutów weryfikacji we właściwościach Movie klasy modelu. Przetestuj walidację Edit przy użyciu metody akcji i zastosowano tę samą walidację.

Dane formularza nie są wysyłane do serwera, dopóki nie wystąpią żadne błędy weryfikacji po stronie klienta. Możesz to sprawdzić, umieszczając punkt przerwania w metodzie HTTP Post przy użyciu narzędzia fiddler lub narzędzi deweloperskich IE F12.

Jak odbywa się walidacja w metodzie Create View i Create Action

Możesz się zastanawiać, jak interfejs użytkownika weryfikacji został wygenerowany bez żadnych aktualizacji kodu w kontrolerze lub widokach. Następna lista pokazuje, jak Create wyglądają metody w MovieController klasie. Nie zmieniają się one w sposób, w jaki zostały utworzone wcześniej w tym samouczku.

public ActionResult Create()
{
    return View();
}
// POST: /Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Pierwsza metoda akcji (HTTP GET) Create wyświetla początkowy formularz Utwórz. Druga wersja ([HttpPost]) obsługuje wpis formularza. Druga Create metoda ( HttpPost wersja) sprawdza ModelState.IsValid , czy film ma jakiekolwiek błędy walidacji. Pobieranie tej właściwości ocenia wszystkie atrybuty weryfikacji, które zostały zastosowane do obiektu. Jeśli obiekt zawiera błędy sprawdzania poprawności, Create metoda redisplays formularza. Jeśli nie ma żadnych błędów, metoda zapisuje nowy film w bazie danych. W naszym przykładzie filmu formularz nie jest publikowany na serwerze po wykryciu błędów walidacji po stronie klienta; druga Create metoda nigdy nie jest wywoływana. Jeśli wyłączysz język JavaScript w przeglądarce, walidacja klienta zostanie wyłączona, a metoda HTTP POST Create sprawdzi ModelState.IsValid , czy film zawiera jakiekolwiek błędy walidacji.

Punkt przerwania można ustawić w metodzie HttpPost Create i sprawdzić, czy metoda nigdy nie jest wywoływana, walidacja po stronie klienta nie będzie przesyłać danych formularza po wykryciu błędów walidacji. Jeśli wyłączysz język JavaScript w przeglądarce, prześlij formularz z błędami, punkt przerwania zostanie trafiony. Nadal uzyskujesz pełną walidację bez języka JavaScript. Na poniższej ilustracji przedstawiono sposób wyłączania języka JavaScript w programie Internet Explorer.

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 t p, a 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 pozycja Włącz skrypt Java jest zakreślina na czerwono.

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

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

Poniżej znajduje się szablon widoku Create.cshtml utworzony wcześniej w samouczku. Jest on używany przez metody akcji pokazane powyżej zarówno do wyświetlania formularza początkowego, jak i do ponownego redysponowania go w przypadku błędu.

@model MvcMovie.Models.Movie
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>
        @*Fields removed for brevity.*@        




        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Zwróć uwagę, że kod używa Html.EditorFor pomocnika do wyprowadzania <input> elementu dla każdej Movie właściwości. Obok tego pomocnika jest wywołanie metody pomocniczej Html.ValidationMessageFor . Te dwie metody pomocnicze działają z obiektem modelu przekazywanym przez kontroler do widoku (w tym przypadku obiektem Movie ). Automatycznie wyszukują atrybuty weryfikacji określone w modelu i wyświetlają odpowiednio komunikaty o błędach.

Naprawdę miło jest to, że ani kontroler, ani Create szablon widoku nie wie nic o rzeczywistych regułach walidacji, które są wymuszane, ani o wyświetlanych konkretnych komunikatach o błędach. Reguły walidacji i ciągi błędów są określone tylko w Movie klasie. Te same reguły sprawdzania poprawności są automatycznie stosowane do Edit widoku i wszystkich innych szablonów widoków, które można utworzyć, aby edytować model.

Jeśli chcesz później zmienić logikę weryfikacji, możesz to zrobić w dokładnie jednym miejscu, dodając atrybuty weryfikacji do modelu (w tym przykładzie movie klasa). Nie trzeba martwić się o niespójność różnych części aplikacji ze sposobem wymuszania reguł — cała logika walidacji zostanie zdefiniowana w jednym miejscu i używana wszędzie. Dzięki temu kod jest bardzo czysty i ułatwia konserwację i rozwijanie. Oznacza to, że będziesz w pełni przestrzegać zasady DRY .

Używanie atrybutów Typu danych

Otwórz plik Movie.cs i sprawdź klasęMovie. System.ComponentModel.DataAnnotations Przestrzeń nazw udostępnia atrybuty formatowania oprócz wbudowanego zestawu atrybutów weryfikacji. Zastosowaliśmy DataType już wartość wyliczenia do daty wydania i pól ceny. Poniższy kod przedstawia ReleaseDate właściwości i Price z odpowiednim DataType atrybutem.

[DataType(DataType.Date)] 
public DateTime ReleaseDate { get; set; }
       
[DataType(DataType.Currency)] 
public decimal Price { get; set; }

Atrybuty DataType udostępniają tylko wskazówki dotyczące aparatu wyświetlania w celu formatowania danych (i podawania atrybutów, takich jak <a> adres URL i <a href="mailto:EmailAddress.com"> adres e-mail). Możesz użyć atrybutu RegularExpression , aby zweryfikować format danych. Atrybut DataType służy do określania typu danych, który jest bardziej szczegółowy niż typ wewnętrzny bazy danych, nieatrybutami walidacji. W tym przypadku chcemy śledzić tylko datę, a nie datę i godzinę. Wyliczenie DataType zawiera wiele typów danych, takich jak Data, Godzina, Numer telefonu, Waluta, Adres e-mail i inne. Atrybut DataType może również umożliwić aplikacji automatyczne udostępnianie funkcji specyficznych dla typu. Na przykład mailto: można utworzyć link dla elementu DataType.EmailAddress, a selektor dat można podać dla elementu DataType.Date w przeglądarkach, które obsługują kod HTML5. Atrybuty DataType emitują atrybuty HTML 5 data- (wymawiane kreski danych), które przeglądarki HTML 5 mogą zrozumieć. Atrybuty DataType nie zapewniają żadnej walidacji.

DataType.Date nie określa formatu wyświetlanej daty. Domyślnie pole danych jest wyświetlane zgodnie z domyślnymi formatami na podstawie informacji o kulturze serwera.

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

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

Ustawienie ApplyFormatInEditMode określa, że określone formatowanie powinno być również stosowane, gdy wartość jest wyświetlana w polu tekstowym do edycji. (Możesz nie chcieć tego dla niektórych pól — na przykład w przypadku wartości walutowych symbol waluty w polu tekstowym do edycji).

Atrybut DisplayFormat można użyć samodzielnie, ale zazwyczaj warto użyć atrybutu DataType. Atrybut DataType przekazuje semantyka danych w przeciwieństwie do sposobu renderowania ich na ekranie i zapewnia następujące korzyści, których nie otrzymujesz za pomocą DisplayFormatpolecenia :

  • Przeglądarka może włączyć funkcje HTML5 (na przykład w celu wyświetlenia kontrolki kalendarza, symbolu waluty odpowiedniego dla ustawień regionalnych, linków poczty e-mail itp.).
  • Domyślnie przeglądarka będzie renderować dane przy użyciu poprawnego formatu na podstawie ustawień regionalnych.
  • Atrybut DataType może umożliwić MVC wybranie odpowiedniego szablonu pola do renderowania danych ( DisplayFormat , jeśli jest używany przez siebie przy użyciu szablonu ciągu). Aby uzyskać więcej informacji, zobacz szablony ASP.NET MVC 2 Brada Wilsona. (Chociaż został napisany dla MVC 2, ten artykuł nadal dotyczy bieżącej wersji ASP.NET MVC).

Jeśli używasz atrybutu DataType z polem daty, musisz również określić DisplayFormat atrybut, aby upewnić się, że pole jest poprawnie renderowane w przeglądarkach Chrome. Aby uzyskać więcej informacji, zobacz ten wątek StackOverflow.

Uwaga

Sprawdzanie poprawności zapytania jQuery nie działa z atrybutem Range i DateTime. Na przykład następujący kod zawsze wyświetla błąd weryfikacji po stronie klienta, nawet jeśli data znajduje się w określonym zakresie:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Aby użyć atrybutu Range z funkcją DateTime, należy wyłączyć walidację daty zapytania jQuery. Zazwyczaj nie jest dobrym rozwiązaniem do kompilowania twardych dat w modelach, więc użycie atrybutu Range i daty/godziny jest zniechęcane.

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

public class Movie
{
   public int ID { get; set; }
   [Required,StringLength(60, MinimumLength = 3)]
   public string Title { get; set; }
   [Display(Name = "Release Date"),DataType(DataType.Date)]
   public DateTime ReleaseDate { get; set; }
   [Required]
   public string Genre { get; set; }
   [Range(1, 100),DataType(DataType.Currency)]
   public decimal Price { get; set; }
   [Required,StringLength(5)]
   public string Rating { get; set; }
}

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