Iteracja 3 — Dodawanie weryfikacji formularza (VB)

autor: Microsoft

Pobierz kod

W trzeciej iteracji dodamy podstawową walidację formularza. Uniemożliwiamy użytkownikom przesyłanie formularza bez wypełniania wymaganych pól formularza. Weryfikujemy również adresy e-mail i numery telefonów.

Tworzenie ASP.NET aplikacji MVC do zarządzania kontaktami (VB)

W tej serii samouczków utworzymy całą aplikację do zarządzania kontaktami od początku do końca. Aplikacja Contact Manager umożliwia przechowywanie informacji kontaktowych — nazw, numerów telefonów i adresów e-mail — dla listy osób.

Tworzymy aplikację za pośrednictwem wielu iteracji. Po każdej iteracji stopniowo ulepszamy aplikację. Celem tego podejścia iteracji wielokrotnej jest umożliwienie zrozumienia przyczyny każdej zmiany.

  • Iteracja #1 — tworzenie aplikacji. W pierwszej iteracji utworzymy menedżera kontaktów w najprostszy możliwy sposób. Dodamy obsługę podstawowych operacji bazy danych: tworzenie, odczytywanie, aktualizowanie i usuwanie (CRUD).

  • Iteracja #2 — sprawia, że aplikacja wygląda ładnie. W tej iteracji poprawiamy wygląd aplikacji, modyfikując domyślną stronę wzorcową ASP.NET widoku MVC i kaskadowy arkusz stylów.

  • Iteracja #3 — dodawanie walidacji formularza. W trzeciej iteracji dodamy podstawową walidację formularza. Uniemożliwiamy użytkownikom przesyłanie formularza bez wypełniania wymaganych pól formularza. Weryfikujemy również adresy e-mail i numery telefonów.

  • Iteracja #4 — luźno połącz aplikację. W tej czwartej iteracji korzystamy z kilku wzorców projektowania oprogramowania, aby ułatwić konserwację i modyfikowanie aplikacji Contact Manager. Na przykład refaktoryzujemy naszą aplikację, aby używać wzorca repozytorium i wzorca wstrzykiwania zależności.

  • Iteracja #5 — tworzenie testów jednostkowych. W piątej iteracji ułatwiamy konserwację i modyfikowanie aplikacji przez dodanie testów jednostkowych. Wyśmiewamy nasze klasy modelu danych i kompilujemy testy jednostkowe dla naszych kontrolerów i logiki walidacji.

  • Iteracja nr 6 — korzystanie z programowania opartego na testach. W tej szóstej iteracji dodamy nową funkcjonalność do naszej aplikacji, pisząc najpierw testy jednostkowe i pisząc kod względem testów jednostkowych. W tej iteracji dodajemy grupy kontaktów.

  • Iteracja #7 — dodawanie funkcji Ajax. W siódmej iteracji poprawiamy czas reakcji i wydajność naszej aplikacji, dodając obsługę Ajax.

Ta iteracja

W tej drugiej iteracji aplikacji Contact Manager dodamy podstawową walidację formularza. Uniemożliwiamy osobom przesyłanie kontaktu bez wprowadzania wartości wymaganych pól formularza. Weryfikujemy również numery telefonów i adresy e-mail (zobacz Rysunek 1).

Okno dialogowe Nowy projekt

Rysunek 01. Formularz z walidacją (kliknij, aby wyświetlić obraz pełnowymiarowy)

W tej iteracji dodamy logikę weryfikacji bezpośrednio do akcji kontrolera. Ogólnie rzecz biorąc, nie jest to zalecany sposób dodawania weryfikacji do aplikacji ASP.NET MVC. Lepszym rozwiązaniem jest umieszczenie logiki walidacji aplikacji w oddzielnej warstwie usługi. W następnej iteracji refaktoryzujemy aplikację Contact Manager, aby zapewnić obsługę aplikacji.

W tej iteracji, aby zachować prostotę, napiszemy cały kod weryfikacji ręcznie. Zamiast pisać kod weryfikacyjny, możemy skorzystać z platformy weryfikacji. Można na przykład użyć bloku aplikacji weryfikacji biblioteki przedsiębiorstwa firmy Microsoft (VAB), aby zaimplementować logikę walidacji dla aplikacji ASP.NET MVC. Aby dowiedzieć się więcej na temat bloku aplikacji weryfikacji, zobacz:

http://msdn.microsoft.com/library/dd203099.aspx

Dodawanie walidacji do widoku tworzenia

Zacznijmy od dodania logiki walidacji do widoku Tworzenie. Na szczęście, ponieważ wygenerowaliśmy widok Tworzenie za pomocą programu Visual Studio, widok Tworzenie zawiera już całą niezbędną logikę interfejsu użytkownika do wyświetlania komunikatów weryfikacji. Widok Utwórz znajduje się na liście 1.

Lista 1 — \Views\Contact\Create.aspx

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of ContactManager.Contact)" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Create</title>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <%= Html.ValidationSummary() %>

    <% Using Html.BeginForm()%>

        <fieldset>
            <legend>Create New Contact</legend>
            <p>
                <label for="FirstName">First Name:</label>
                <%= Html.TextBox("FirstName") %>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">Last Name:</label>
                <%= Html.TextBox("LastName") %>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
            <p>
                <label for="Phone">Phone:</label>
                <%= Html.TextBox("Phone") %>
                <%= Html.ValidationMessage("Phone", "*") %>
            </p>
            <p>
                <label for="Email">Email:</label>
                <%= Html.TextBox("Email") %>
                <%= Html.ValidationMessage("Email", "*") %>
            </p>
            <p class="submit">
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% End Using %>

</asp:Content>

Klasa field-validation-error służy do stylu danych wyjściowych renderowanych przez pomocnika Html.ValidationMessage(). Klasa input-validation-error służy do stylu pola tekstowego (danych wejściowych) renderowanych przez pomocnik Html.TextBox(). Klasa validation-summary-errors służy do stylu listy nieurządkowanej renderowanej przez pomocnik Html.ValidationSummary().

Uwaga

Klasy arkuszy stylów opisane w tej sekcji można zmodyfikować, aby dostosować wygląd komunikatów o błędach weryfikacji.

Dodawanie logiki walidacji do akcji tworzenia

W tej chwili widok Tworzenie nigdy nie wyświetla komunikatów o błędach weryfikacji, ponieważ nie napisaliśmy logiki w celu wygenerowania żadnych komunikatów. Aby wyświetlić komunikaty o błędach weryfikacji, należy dodać komunikaty o błędach do elementu ModelState.

Uwaga

Metoda UpdateModel() automatycznie dodaje komunikaty o błędach do elementu ModelState, gdy występuje błąd podczas przypisywania wartości pola formularza do właściwości. Jeśli na przykład próbujesz przypisać ciąg "apple" do właściwości BirthDate, która akceptuje wartości DateTime, metoda UpdateModel() dodaje błąd do modelu ModelState.

Zmodyfikowana metoda Create() w liście List 2 zawiera nową sekcję, która weryfikuje właściwości klasy Contact przed wstawieniem nowego kontaktu do bazy danych.

Lista 2 — Controllers\ContactController.vb (Tworzenie przy użyciu walidacji)

<AcceptVerbs(HttpVerbs.Post)> _
Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
    ' Validation logic
    If contactToCreate.FirstName.Trim().Length = 0 Then
        ModelState.AddModelError("FirstName", "First name is required.")
    End If
    If contactToCreate.LastName.Trim().Length = 0 Then
        ModelState.AddModelError("LastName", "Last name is required.")
    End If
    If (contactToCreate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToCreate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
        ModelState.AddModelError("Phone", "Invalid phone number.")
    End If        
    If (contactToCreate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToCreate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
        ModelState.AddModelError("Email", "Invalid email address.")
    End If
    If Not ModelState.IsValid Then
        Return View()
    End If

    ' Database logic
    Try
        _entities.AddToContactSet(contactToCreate)
        _entities.SaveChanges()
        Return RedirectToAction("Index")
    Catch
        Return View()
    End Try
End Function

Sekcja sprawdzania poprawności wymusza cztery odrębne reguły walidacji:

  • Właściwość FirstName musi mieć długość większą niż zero (i nie może składać się wyłącznie z spacji)
  • Właściwość LastName musi mieć długość większą niż zero (i nie może składać się wyłącznie z spacji)
  • Jeśli właściwość Phone ma wartość (ma długość większą niż 0), właściwość Phone musi być zgodna z wyrażeniem regularnym.
  • Jeśli właściwość Email ma wartość (ma długość większą niż 0), właściwość Email musi być zgodna z wyrażeniem regularnym.

W przypadku naruszenia reguły sprawdzania poprawności komunikat o błędzie jest dodawany do modelu ModelState przy użyciu metody AddModelError(). Po dodaniu komunikatu do elementu ModelState należy podać nazwę właściwości i tekst komunikatu o błędzie weryfikacji. Ten komunikat o błędzie jest wyświetlany w widoku przez metody pomocnika Html.ValidationSummary() i Html.ValidationMessage().

Po wykonaniu reguł walidacji właściwość IsValid elementu ModelState jest sprawdzana. Właściwość IsValid zwraca wartość false, gdy wszystkie komunikaty o błędach weryfikacji zostały dodane do elementu ModelState. Jeśli walidacja zakończy się niepowodzeniem, formularz Tworzenie zostanie ponownie wyeksponowy z komunikatami o błędach.

Uwaga

Mam wyrażenia regularne do weryfikowania numeru telefonu i adresu e-mail z repozytorium wyrażeń regularnych pod adresem http://regexlib.com

Dodawanie logiki walidacji do akcji edycji

Akcja Edit() aktualizuje kontakt. Akcja Edit() musi wykonać dokładnie tę samą walidację co akcja Create(). Zamiast duplikować ten sam kod weryfikacji, należy refaktoryzować kontroler kontaktów, aby akcje Create() i Edit() wywoływać tę samą metodę weryfikacji.

Zmodyfikowana klasa kontrolera kontaktów znajduje się na liście 3. Ta klasa ma nową metodę ValidateContact(), która jest wywoływana zarówno w ramach akcji Create() i Edit().

Lista 3 — Controllers\ContactController.vb

Public Class ContactController
    Inherits System.Web.Mvc.Controller

    Private _entities As New ContactManagerDBEntities()

    Protected Sub ValidateContact(contactToValidate As Contact)
        If contactToValidate.FirstName.Trim().Length = 0 Then
            ModelState.AddModelError("FirstName", "First name is required.")
        End If
        If contactToValidate.LastName.Trim().Length = 0 Then
            ModelState.AddModelError("LastName", "Last name is required.")
        End If
        If (contactToValidate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToValidate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
            ModelState.AddModelError("Phone", "Invalid phone number.")
        End If        
        If (contactToValidate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToValidate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
            ModelState.AddModelError("Email", "Invalid email address.")
        End If
    End Sub

    '
    ' GET: /Contact

    Function Index() As ActionResult
        Return View(_entities.ContactSet.ToList())
    End Function

    '
    ' GET: /Contact/Create

    Function Create() As ActionResult
        Return View()
    End Function

    '
    ' POST: /Contact/Create

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToCreate)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            _entities.AddToContactSet(contactToCreate)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Edit/5

    Function Edit(ByVal id As Integer) As ActionResult
        Dim contactToEdit = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToEdit)
    End Function

    '
    ' POST: /Contact/Edit/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Edit(ByVal contactToEdit As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToEdit)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToEdit.Id _
                             select c).FirstOrDefault()
            _entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Delete/5

    Function Delete(ByVal id As Integer) As ActionResult
        Dim contactToDelete = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToDelete)
    End Function

    '
    ' POST: /Contact/Delete/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Delete(ByVal contactToDelete As Contact) As ActionResult
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToDelete.Id _
                             select c).FirstOrDefault()
            _entities.DeleteObject(originalContact)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

End Class

Podsumowanie

W tej iteracji dodaliśmy podstawową walidację formularza do naszej aplikacji Contact Manager. Nasza logika walidacji uniemożliwia użytkownikom przesyłanie nowego kontaktu lub edytowanie istniejącego kontaktu bez podawania wartości właściwości FirstName i LastName. Ponadto użytkownicy muszą podać prawidłowe numery telefonów i adresy e-mail.

W tej iteracji dodaliśmy logikę walidacji do naszej aplikacji Contact Manager w najprostszy możliwy sposób. Jednak mieszanie logiki walidacji do logiki kontrolera spowoduje powstanie problemów w dłuższej perspektywie. Nasza aplikacja będzie trudniejsza do utrzymania i modyfikowania w czasie.

W następnej iteracji refaktoryzujemy logikę walidacji i logikę dostępu do bazy danych z naszych kontrolerów. Skorzystamy z kilku zasad projektowania oprogramowania, aby umożliwić nam tworzenie bardziej luźno sprzężonych i bardziej konserwowalnych aplikacji.