Udostępnij za pośrednictwem


Badanie metod edycji i widoku edycji (VB)

Autor: Rick Anderson

Ten samouczek zawiera podstawowe informacje na temat tworzenia aplikacji internetowej MVC ASP.NET przy użyciu dodatku Microsoft Visual Web Developer 2010 Express Service Pack 1, który jest bezpłatną wersją programu Microsoft Visual Studio. Przed rozpoczęciem upewnij się, że zostały zainstalowane wymagania wstępne wymienione poniżej. Wszystkie te elementy można zainstalować, klikając następujący link: Instalator platformy internetowej. Alternatywnie można indywidualnie zainstalować wymagania wstępne, korzystając z następujących linków:

Jeśli używasz programu Visual Studio 2010 zamiast Visual Web Developer 2010, zainstaluj wymagania wstępne, klikając następujący link: Wymagania wstępne programu Visual Studio 2010.

Projekt Visual Web Developer z kodem źródłowym VB.NET jest dostępny do dołączenia do tego tematu. Pobierz wersję VB.NET. Jeśli wolisz język C#, przejdź do wersji języka C# tego samouczka.

W tej sekcji zapoznasz się z wygenerowanymi metodami akcji i widokami kontrolera filmu. Następnie dodasz stronę wyszukiwania niestandardowego.

Uruchom aplikację i przejdź do Movies kontrolera, dołączając /Movies do adresu URL na pasku adresu przeglądarki. Przytrzymaj wskaźnik myszy na linku Edytuj , aby wyświetlić adres URL, z którym się łączy.

Zrzut ekranu przedstawiający aplikację przenoszenia MVC z linkiem Edytuj dla jednego z wybranych filmów.

Link Edytuj został wygenerowany przez metodę Html.ActionLink w widoku Views\Movies\Index.vbhtml :

@Html.ActionLink("Edit", "Edit", New With {.id = currentItem.ID}) |

Zrzut ekranu przedstawia link Html.ActionLink w edytorze kodu.

Obiekt Html jest pomocnikiem, który jest uwidoczniony przy użyciu właściwości w klasie bazowej WebViewPage . ActionLink Metoda pomocnika ułatwia dynamiczne generowanie hiperlinków HTML, które łączą się z metodami akcji na kontrolerach. Pierwszym argumentem ActionLink metody jest tekst linku do renderowania (na przykład <a>Edit Me</a>). Drugi argument to nazwa metody akcji do wywołania. Ostatnim argumentem jest anonimowy obiekt , który generuje dane trasy (w tym przypadku identyfikator 4).

Wygenerowany link pokazany na poprzedniej ilustracji to http://localhost:xxxxx/Movies/Edit/4. Trasa domyślna przyjmuje wzorzec {controller}/{action}/{id}adresu URL . W związku z tym ASP.NET przekłada się http://localhost:xxxxx/Movies/Edit/4 na żądanie do Edit metody Movies akcji kontrolera z parametrem ID równym 4.

Parametry metody akcji można również przekazać przy użyciu ciągu zapytania. Na przykład adres URL http://localhost:xxxxx/Movies/Edit?ID=4 przekazuje również parametr ID 4 do Edit metody Movies akcji kontrolera.

EditQueryString

Movies Otwórz kontroler. Poniżej przedstawiono dwie Edit metody akcji.

'
' GET: /Movies/Edit/5

Function Edit(id As Integer) As ViewResult
    Dim movie As Movie = db.Movies.Find(id)
    Return View(movie)
End Function

'
' POST: /Movies/Edit/5

<HttpPost()>
Function Edit(movie As Movie) As ActionResult
    If ModelState.IsValid Then
        db.Entry(movie).State = EntityState.Modified
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(movie)
End Function

Zwróć uwagę, że druga Edit metoda akcji jest poprzedzona atrybutem HttpPost . Ten atrybut określa, że przeciążenie Edit metody można wywołać tylko dla żądań POST. Atrybut można zastosować HttpGet do pierwszej metody edycji, ale nie jest to konieczne, ponieważ jest to ustawienie domyślne. (Odwołujemy się do metod akcji, które są niejawnie przypisywane HttpGet atrybut jako HttpGet metody).

Metoda HttpGet Edit pobiera parametr identyfikatora filmu, wyszukuje film przy użyciu metody Entity Framework Find i zwraca wybrany film do widoku Edytuj. Gdy system tworzenia szkieletów utworzył widok Edycji, przeanalizował klasę Movie i utworzył kod renderujący <label> i <input> elementy dla każdej właściwości klasy. W poniższym przykładzie pokazano wygenerowany widok Edycji:

@ModelType MvcMovie.Movie

@Code
    ViewData("Title") = "Edit"
End Code

<h2>Edit</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@Using Html.BeginForm()
    @Html.ValidationSummary(True)
    @<fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(Function(model) model.ID)

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Title)
            @Html.ValidationMessageFor(Function(model) model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ReleaseDate)
            @Html.ValidationMessageFor(Function(model) model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Genre)
            @Html.ValidationMessageFor(Function(model) model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Price)
            @Html.ValidationMessageFor(Function(model) model.Price)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
End Using

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Zwróć uwagę, że szablon widoku zawiera instrukcję @ModelType MvcMovie.Models.Movie w górnej części pliku — określa, że widok oczekuje modelu dla szablonu widoku typu Movie.

Kod szkieletowy używa kilku metod pomocnika w celu usprawnienia znaczników HTML. Pomocnik Html.LabelFor wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik Html.EditorFor wyświetla element HTML <input> . Pomocnik Html.ValidationMessageFor wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.

Uruchom aplikację i przejdź do adresu URL /Movies . Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Kod HTML na stronie wygląda podobnie do poniższego przykładu. (Znacznik menu został wykluczony w celu uzyskania jasności).

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Edit</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>MVC Movie App</h1>
            </div>
           ...
        </header>
        <section id="main">

<h2>Edit</h2>

<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>

<form action="/Movies/Edit/4" method="post">    <fieldset>
        <legend>Movie</legend>

        <input data-val="true" data-val-number="The field ID must be a number." 
    data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

        <div class="editor-label">
            <label for="Title">Title</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" />
            <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="ReleaseDate">ReleaseDate</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-required="The ReleaseDate field is required." 
    id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" />
            <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Genre">Genre</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" />
            <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Price">Price</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." 
    data-val-required="The Price field is required." id="Price" name="Price" type="text" value="9.99" />
            <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</form>
<div>
    <a href="/Movies">Back to List</a>
</div>

        </section>
        <footer>
        </footer>
    </div>
</body>
</html>

<input> Elementy znajdują się w elemecie HTML<form>, którego action atrybut jest ustawiony na publikowanie na /Movies/Edit URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu przycisku Edytuj .

Przetwarzanie żądania POST

Na poniższej HttpPost liście przedstawiono wersję Edit metody akcji.

'
' POST: /Movies/Edit/5

<HttpPost()>
Function Edit(movie As Movie) As ActionResult
    If ModelState.IsValid Then
        db.Entry(movie).State = EntityState.Modified
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(movie)
End Function

Powiązanie modelu platformy ASP.NET przyjmuje opublikowane wartości formularza i tworzy Movie obiekt, który jest przekazywany jako movie parametr. Zaewidencjonuj ModelState.IsValid kod sprawdza, czy dane przesłane w formularzu mogą służyć do modyfikowania Movie obiektu. Jeśli dane są prawidłowe, kod zapisuje dane filmu w Movies kolekcji MovieDBContext wystąpienia. Następnie kod zapisuje nowe dane filmu w bazie danych, wywołując SaveChanges metodę MovieDBContext, która utrwala zmiany w bazie danych. Po zapisaniu danych kod przekierowuje użytkownika do Index metody MoviesController akcji klasy, co powoduje wyświetlenie zaktualizowanego filmu na liście filmów.

Jeśli wartości opublikowane nie są prawidłowe, są one odtwarzane w formularzu. Pomocnicy Html.ValidationMessageFor w szablonie widoku Edit.vbhtml dbają o wyświetlanie odpowiednich komunikatów o błędach.

abcNotValid

Uwaga dotycząca ustawień regionalnych Jeśli zwykle pracujesz z ustawieniami regionalnymi innymi niż angielski, zobacz Obsługa ASP.NET walidacji MVC 3 z ustawieniami regionalnymi innymi niż angielski.

Zwiększenie niezawodności metody edycji

HttpGet Edit Metoda wygenerowana przez system tworzenia szkieletów nie sprawdza, czy identyfikator przekazany do niego jest prawidłowy. Jeśli użytkownik usunie segment identyfikatora z adresu URL (http://localhost:xxxxx/Movies/Edit), zostanie wyświetlony następujący błąd:

Null_ID

Użytkownik może również przekazać identyfikator, który nie istnieje w bazie danych, na przykład http://localhost:xxxxx/Movies/Edit/1234. Aby rozwiązać ten problem, możesz wprowadzić dwie zmiany w metodzie HttpGet Edit akcji. Najpierw zmień ID parametr tak, aby miał wartość domyślną zero, gdy identyfikator nie jest jawnie przekazywany. Możesz również sprawdzić, czy Find metoda rzeczywiście znalazła film przed zwróceniem obiektu filmu do szablonu widoku. Zaktualizowana Edit metoda jest pokazana poniżej.

Public Function Edit(Optional ByVal id As Integer = 0) As ActionResult
    Dim movie As Movie = db.Movies.Find(id)
    If movie Is Nothing Then
        Return HttpNotFound()
    End If
    Return View(movie)
End Function

Jeśli nie znaleziono filmu, metoda jest wywoływana HttpNotFound .

HttpGet Wszystkie metody są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index), a następnie przekazują model do widoku. Metoda Create przekazuje pusty obiekt filmu do widoku Create. Wszystkie metody, które tworzą, edytują, usuwają lub w inny sposób modyfikują dane, robią to w HttpPost przeciążeniu metody . Modyfikowanie danych w metodzie HTTP GET jest zagrożeniem bezpieczeństwa. Modyfikowanie danych w metodzie GET narusza również najlepsze rozwiązania HTTP i wzorzec REST architektury, który określa, że żądania GET nie powinny zmieniać stanu aplikacji. Innymi słowy wykonanie operacji GET powinno być bezpieczną operacją, która nie ma skutków ubocznych.

Dodawanie metody wyszukiwania i widoku wyszukiwania

W tej sekcji dodasz metodę SearchIndex akcji, która umożliwia wyszukiwanie filmów według gatunku lub nazwy. Będzie to dostępne przy użyciu adresu URL /Movies/SearchIndex . Żądanie wyświetli formularz HTML zawierający elementy wejściowe, które użytkownik może wypełnić, aby wyszukać film. Gdy użytkownik prześle formularz, metoda akcji pobierze wartości wyszukiwania opublikowane przez użytkownika i użyje wartości do przeszukania bazy danych.

SearchIndx_SM

Wyświetlanie formularza SearchIndex

Zacznij od dodania SearchIndex metody akcji do istniejącej MoviesController klasy. Metoda zwróci widok zawierający formularz HTML. Oto kod:

Public Function SearchIndex(ByVal searchString As String) As ActionResult
    Dim movies = From m In db.Movies
                 Select m 

    If Not String.IsNullOrEmpty(searchString) Then 
        movies = movies.Where(Function(s) s.Title.Contains(searchString)) 
    End If
    Return View(movies) 
End Function

Pierwszy wiersz SearchIndex metody tworzy następujące zapytanie LINQ w celu wybrania filmów:

Dim movies = From m In db.Movies    Select m

Zapytanie jest zdefiniowane w tym momencie, ale nie zostało jeszcze uruchomione względem magazynu danych.

searchString Jeśli parametr zawiera ciąg, zapytanie filmów jest modyfikowane w celu filtrowania wartości ciągu wyszukiwania przy użyciu następującego kodu:

Jeśli nie string.IsNullOrEmpty(searchString), wówczas
filmy = filmy. Where(Function(Title.Contains(searchString))
Zakończ, jeśli

Zapytania LINQ nie są wykonywane podczas ich definiowania lub modyfikowania przez wywołanie metody takiej jak Where lub OrderBy. Zamiast tego wykonywanie zapytania jest odroczone, co oznacza, że obliczanie wyrażenia jest opóźnione, dopóki nie zostanie rzeczywiście iterowana wartość lub ToList metoda jest wywoływana. W przykładzie SearchIndex zapytanie jest wykonywane w widoku SearchIndex. Aby uzyskać więcej informacji na temat odroczonego wykonywania zapytań, zobacz Wykonywanie zapytań.

Teraz możesz zaimplementować SearchIndex widok, który wyświetli formularz użytkownikowi. Kliknij prawym przyciskiem myszy wewnątrz SearchIndex metody, a następnie kliknij polecenie Dodaj widok. W oknie dialogowym Dodawanie widoku określ, że zamierzasz przekazać Movie obiekt do szablonu widoku jako klasę modelu. Na liście szablonów szkieletu wybierz pozycję Lista, a następnie kliknij przycisk Dodaj.

AddSearchView

Po kliknięciu przycisku Dodaj zostanie utworzony szablon widok Views\Movies\SearchIndex.vbhtml. Ponieważ wybrano pozycję Lista na liście szablonów szkieletu , w widoku automatycznie wygenerowano (szkielet) wygenerowaną automatycznie (szkieletową) zawartość domyślną. Tworzenie szkieletu spowodowało utworzenie formularza HTML. Przeanalizowała klasę Movie i utworzyła kod, aby renderować <label> elementy dla każdej właściwości klasy. Na poniższej liście przedstawiono widok Utwórz, który został wygenerowany:

@ModelType IEnumerable(Of MvcMovie.Movie)

@Code
    ViewData("Title") = "SearchIndex"
End Code

<h2>SearchIndex</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            Title
        </th>
        <th>
            ReleaseDate
        </th>
        <th>
            Genre
        </th>
        <th>
            Price
        </th>
        <th></th>
    </tr>

@For Each item In Model
    Dim currentItem = item
    @<tr>
        <td>
            @Html.DisplayFor(Function(modelItem) currentItem.Title)
        </td>
        <td>
            @Html.DisplayFor(Function(modelItem) currentItem.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(Function(modelItem) currentItem.Genre)
        </td>
        <td>
            @Html.DisplayFor(Function(modelItem) currentItem.Price)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", New With {.id = currentItem.ID}) |
            @Html.ActionLink("Details", "Details", New With {.id = currentItem.ID}) |
            @Html.ActionLink("Delete", "Delete", New With {.id = currentItem.ID})
        </td>
    </tr>
Next

</table>

Uruchom aplikację i przejdź do folderu /Movies/SearchIndex. Dołącz ciąg zapytania, taki jak ?searchString=ghost do adresu URL. Zostaną wyświetlone przefiltrowane filmy.

SearchQryStr

Jeśli zmienisz podpis SearchIndex metody na parametr o nazwie id, id parametr będzie zgodny z symbolem {id} zastępczym dla tras domyślnych ustawionych w pliku Global.asax .

{controller}/{action}/{id}

Zmodyfikowana SearchIndex metoda wygląda następująco:

Public Function SearchIndex(ByVal id As String) As ActionResult
Dim searchString As String = id
Dim movies = From m In db.Movies
             Select m

If Not String.IsNullOrEmpty(searchString) Then
    movies = movies.Where(Function(s) s.Title.Contains(searchString))
End If

Return View(movies)
End Function

Teraz możesz przekazać tytuł wyszukiwania jako dane trasy (segment adresu URL) zamiast jako wartość ciągu zapytania.

SearchRouteData

Nie można jednak oczekiwać, że użytkownicy będą modyfikować adres URL za każdym razem, gdy chcą wyszukać film. Teraz dodasz interfejs użytkownika, aby ułatwić filtrowanie filmów. Jeśli zmieniono podpis metody w celu przetestowania sposobu przekazywania parametru SearchIndex identyfikatora powiązanego z trasą, zmień go z powrotem, aby SearchIndex metoda przyjmuje parametr ciągu o nazwie searchString:

Otwórz plik Views\Movies\SearchIndex.vbhtml, a tuż po @Html.ActionLink("Create New", "Create")pliku dodaj następujące polecenie:

@Code
    ViewData("Title") = "SearchIndex"
    Using (Html.BeginForm())
         @<p> Title: @Html.TextBox("SearchString") 
         <input type="submit" value="Filter" /></p>
        End Using
End Code

Pomocnik Html.BeginForm tworzy tag otwierający <form> . Pomocnik Html.BeginForm powoduje opublikowanie formularza jako samego siebie, gdy użytkownik prześle formularz, klikając przycisk Filtruj.

Uruchom aplikację i spróbuj wyszukać film.

SearchIndxIE9_title

Nie ma HttpPost przeciążenia SearchIndex metody . Nie potrzebujesz go, ponieważ metoda nie zmienia stanu aplikacji, po prostu filtrując dane. Jeśli dodano następującą HttpPost SearchIndex metodę, wywołanie akcji będzie zgodne z HttpPost SearchIndex metodą, a HttpPost SearchIndex metoda zostanie uruchomiona, jak pokazano na poniższej ilustracji.

<HttpPost()>
 Public Function SearchIndex(ByVal fc As FormCollection, ByVal searchString As String) As String
     Return "<h3> From [HttpPost]SearchIndex: " & searchString & "</h3>"
 End Function

SearchPostGhost

Dodawanie wyszukiwania według gatunku

Jeśli dodano HttpPost wersję SearchIndex metody, usuń ją teraz.

Następnie dodasz funkcję umożliwiającą użytkownikom wyszukiwanie filmów według gatunku. Zastąp metodę SearchIndex poniższym kodem:

Public Function SearchIndex(ByVal movieGenre As String, ByVal searchString As String) As ActionResult
    Dim GenreLst = New List(Of String)()

    Dim GenreQry = From d In db.Movies
                   Order By d.Genre
                   Select d.Genre
    GenreLst.AddRange(GenreQry.Distinct())
    ViewBag.movieGenre = New SelectList(GenreLst)

    Dim movies = From m In db.Movies
                 Select m

    If Not String.IsNullOrEmpty(searchString) Then
        movies = movies.Where(Function(s) s.Title.Contains(searchString))
    End If

    If String.IsNullOrEmpty(movieGenre) Then
        Return View(movies)
    Else
        Return View(movies.Where(Function(x) x.Genre = movieGenre))
    End If

End Function

Ta wersja SearchIndex metody przyjmuje dodatkowy parametr, a mianowicie movieGenre. Pierwsze kilka wierszy kodu tworzy List obiekt do przechowywania gatunków filmów z bazy danych.

Poniższy kod to zapytanie LINQ, które pobiera wszystkie gatunki z bazy danych.

Dim GenreQry = From d In db.Movies
                   Order By d.Genre
                   Select d.Genre

Kod używa AddRange metody kolekcji ogólnej List , aby dodać wszystkie odrębne gatunki do listy. (Bez Distinct modyfikatora zostaną dodane zduplikowane gatunki — na przykład komedia zostanie dodana dwukrotnie w naszym przykładzie). Następnie kod przechowuje listę gatunków w ViewBag obiekcie.

Poniższy kod pokazuje, jak sprawdzić movieGenre parametr. Jeśli kod nie jest pusty, ogranicza zapytanie filmów, aby ograniczyć wybrane filmy do określonego gatunku.

If String.IsNullOrEmpty(movieGenre) Then
        Return View(movies)
    Else
        Return View(movies.Where(Function(x) x.Genre = movieGenre))
    End If

Dodawanie znaczników do widoku SearchIndex w celu obsługi wyszukiwania według gatunku

Html.DropDownList Dodaj pomocnika do pliku Views\Movies\SearchIndex.vbhtml tuż przed pomocnikiemTextBox. Ukończony znacznik jest pokazany poniżej:

<p>
    @Html.ActionLink("Create New", "Create")
    @Code
    ViewData("Title") = "SearchIndex"
    Using (Html.BeginForm())
         @<p> Genre: @Html.DropDownList("movieGenre", "All")
         Title: @Html.TextBox("SearchString") 
         <input type="submit" value="Filter" /></p>
        End Using
End Code
</p>

Uruchom aplikację i przejdź do folderu /Movies/SearchIndex. Spróbuj wyszukać według gatunku, według nazwy filmu i obu kryteriów.

W tej sekcji zbadano metody akcji CRUD i widoki wygenerowane przez platformę. Utworzono metodę akcji wyszukiwania i widok, która umożliwia użytkownikom wyszukiwanie według tytułu i gatunku filmu. W następnej sekcji dowiesz się, jak dodać właściwość do Movie modelu i jak dodać inicjator, który automatycznie utworzy testową bazę danych.