Udostępnij za pośrednictwem


Badanie metod i widoków akcji edycji kontrolera filmu

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 w ASP.NET Core, oparty na stronach model programowania, który ułatwia tworzenie internetowego interfejsu użytkownika i jest bardziej produktywne. 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 zapoznasz się z wygenerowanymi Edit metodami akcji i widokami kontrolera filmu. Ale najpierw zajmiemy krótką przekierowanie, aby data wydania wyglądała lepiej. Otwórz plik Models\Movie.cs i dodaj wyróżnione wiersze pokazane poniżej:

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        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; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }

    public class MovieDBContext : DbContext
    {
        public DbSet<Movie> Movies { get; set; }
    }
}

Możesz również ustawić określoną kulturę daty w następujący sposób:

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

W następnym samouczku omówimy elementy DataAnnotations . Atrybut Wyświetlania określa, co ma być wyświetlane dla nazwy pola (w tym przypadku "Data wydania" zamiast "Data wydania"). Atrybut DataType określa typ danych, w tym przypadku jest to data, więc informacje o godzinie przechowywane w polu nie są wyświetlane. Atrybut DisplayFormat jest wymagany w przypadku usterki w przeglądarce Chrome, która niepoprawnie renderuje formaty dat.

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

EditLink_sm

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

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

Html.ActionLink

Obiekt Html jest pomocnika uwidocznionego przy użyciu właściwości w klasie bazowej System.Web.Mvc.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>). Drugim argumentem jest nazwa metody akcji do wywołania (w tym przypadku Edit akcja). Ostatnim argumentem jest anonimowy obiekt , który generuje dane trasy (w tym przypadku identyfikator 4).

Wygenerowany link pokazany na poprzedniej ilustracji to http://localhost:1234/Movies/Edit/4. Trasa domyślna (ustanowiona w pliku App_Start\RouteConfig.cs) przyjmuje wzorzec {controller}/{action}/{id}adresu URL . W związku z tym ASP.NET przekłada się http://localhost:1234/Movies/Edit/4 na żądanie do Edit metody Movies akcji kontrolera z parametrem ID równym 4. Sprawdź poniższy kod z pliku App_Start\RouteConfig.cs . Metoda MapRoute służy do kierowania żądań HTTP do poprawnego kontrolera i metody akcji i podawania opcjonalnego parametru identyfikatora. Metoda MapRoute jest również używana przez klasy HtmlHelpers , takie jak ActionLink generowanie adresów URL na podstawie kontrolera, metody akcji i wszystkich danych trasy.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", 
            id = UrlParameter.Optional }
    );
}

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

EditQueryString

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

// GET: /Movies/Edit/5
public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    return View(movie);
}

// POST: /Movies/Edit/5
// 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 Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Zwróć uwagę, że druga Edit metoda akcji jest poprzedzona atrybutem HttpPost . Ten atrybut określa, że przeciążenie Edit metody może być wywoływane 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). Atrybut Bind to kolejny ważny mechanizm zabezpieczeń, który uniemożliwia hakerom nadmierne delegowanie danych do modelu. Właściwości należy uwzględnić tylko w atrybucie bind, który chcesz zmienić. Możesz przeczytać o overpostowanie i atrybut powiązania w mojej notatce zabezpieczeń overposting. W prostym modelu używanym w tym samouczku będziemy wiązać wszystkie dane w modelu. Atrybut ValidateAntiForgeryToken służy do zapobiegania fałszerzowaniu żądania i jest sparowany z plikiem @Html.AntiForgeryToken() widoku edycji (Views\Movies\Edit.cshtml), poniżej przedstawiono część:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.ID)

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

@Html.AntiForgeryToken() Generuje ukryty token chroniący przed fałszerzami, który musi być zgodny z Edit metodą Movies kontrolera. Więcej informacji na temat fałszowania żądań między witrynami (znanego również jako XSRF lub CSRF) można przeczytać w samouczku XSRF/CSRF Prevention in MVC (Zapobieganie żądaniom XSRF/CSRF).

Metoda HttpGetEdit pobiera parametr identyfikatora filmu, wyszukuje film przy użyciu metody Entity Framework Find i zwraca wybrany film do widoku Edycja. Jeśli nie można odnaleźć filmu, zwracana jest metoda HttpNotFound . Kiedy system tworzenia szkieletów utworzył widok Edycja, zbadał klasę Movie i utworzył kod do renderowania <label> i <input> elementów dla każdej właściwości klasy. W poniższym przykładzie pokazano widok Edycji wygenerowany przez system tworzenia szkieletów programu Visual Studio:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.ID)

        <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>
        <div class="form-group">
            @Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ReleaseDate)
                @Html.ValidationMessageFor(model => model.ReleaseDate)
            </div>
        </div>
        @*Genre and Price removed for brevity.*@        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Zwróć uwagę, że szablon widoku ma instrukcję @model 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", "Genre" lub "Price"). Pomocnik Html.EditorFor renderuje 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 dla elementu formularza jest pokazany poniżej.

<form action="/movies/Edit/4" method="post">
   <input name="__RequestVerificationToken" type="hidden" value="UxY6bkQyJCXO3Kn5AXg-6TXxOj6yVBi9tghHaQ5Lq_qwKvcojNXEEfcbn-FGh_0vuw4tS_BRk7QQQHlJp8AP4_X4orVNoQnp2cd8kXhykS01" />  <fieldset class="form-horizontal">
      <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="control-group">
         <label class="control-label" for="Title">Title</label>
         <div class="controls">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="GhostBusters" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Title" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="ReleaseDate">Release Date</label>
         <div class="controls">
            <input class="text-box single-line" data-val="true" data-val-date="The field Release Date must be a date." data-val-required="The Release Date field is required." id="ReleaseDate" name="ReleaseDate" type="date" value="1/1/1984" />
            <span class="field-validation-valid help-inline" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="Genre">Genre</label>
         <div class="controls">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Comedy" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="Price">Price</label>
         <div class="controls">
            <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="7.99" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Price" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="form-actions no-color">
         <input type="submit" value="Save" class="btn" />
      </div>
   </fieldset>
</form>

<input> Elementy znajdują się w elemecie HTML<form>, którego action atrybut jest ustawiony na publikowanie w adresie URL /Movies/Edit. Dane formularza zostaną opublikowane na serwerze po kliknięciu przycisku Zapisz . Drugi wiersz przedstawia ukryty token XSRF wygenerowany przez wywołanie @Html.AntiForgeryToken() .

Przetwarzanie żądania POST

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

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Atrybut ValidateAntiForgeryToken weryfikuje token XSRF wygenerowany przez @Html.AntiForgeryToken() wywołanie w widoku.

Powiązanie modelu MVC ASP.NET przyjmuje opublikowane wartości formularza i tworzy Movie obiekt, który jest przekazywany jako movie parametr. Funkcja ModelState.IsValid sprawdza, czy dane przesłane w formularzu mogą służyć do modyfikowania (edytowania Movie lub aktualizowania) obiektu. Jeśli dane są prawidłowe, dane filmu są zapisywane w Movies kolekcji db(MovieDBContext wystąpienia). Nowe dane filmu są zapisywane w bazie danych przez wywołanie SaveChanges metody MovieDBContext. Po zapisaniu danych kod przekierowuje użytkownika do Index metody MoviesController akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.

Gdy tylko walidacja po stronie klienta ustali, że wartość pola jest nieprawidłowa, zostanie wyświetlony komunikat o błędzie. Jeśli język JavaScript jest wyłączony, walidacja po stronie klienta jest wyłączona. Jednak serwer wykrywa, że opublikowane wartości są nieprawidłowe, a wartości formularza są odtwarzane ponownie z komunikatami o błędach.

Walidacja zostanie dokładniej zbadana w dalszej części tego samouczka.

Pomocnicy Html.ValidationMessageFor w szablonie widoku Edit.cshtml dbają o wyświetlanie odpowiednich komunikatów o błędach.

abcNotValid

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 Utwórz. Wszystkie metody, które tworzą, edytują, usuwają lub w inny sposób modyfikują dane w HttpPost przeciążeniu metody . Modyfikowanie danych w metodzie HTTP GET jest zagrożeniem bezpieczeństwa, zgodnie z opisem we wpisie we wpisie w blogu ASP.NET porada MVC nr 46 — nie używaj linków usuwania, ponieważ tworzą one luki w zabezpieczeniach. 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 wykonywanie operacji GET powinno być bezpieczną operacją, która nie ma skutków ubocznych i nie modyfikuje utrwalone dane.

Sprawdzanie poprawności trybu jQuery dla ustawień regionalnych innych niż angielski

Jeśli używasz komputera US-English, możesz pominąć tę sekcję i przejść do następnego samouczka. Tę wersję tego samouczka można pobrać tutaj. Aby zapoznać się z doskonałym dwuczęściowym samouczkiem dotyczącym internacjonalizacji, zobacz ASP.NET MVC 5 Internationalization Nadeema.

Uwaga

Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i formatów dat innych niż US-English, należy uwzględnić globalize.js i określone kultury/pliki globalize.cultures.js (z https://github.com/jquery/globalize ) i JavaScript do użycia .Globalize.parseFloat Walidację języka jQuery innego niż angielski można pobrać z narzędzia NuGet. (Nie instaluj funkcji Globalizuj, jeśli używasz ustawień regionalnych w języku angielskim).

  1. W menu Narzędzia kliknij pozycję Menedżer pakietów NuGet, a następnie kliknij pozycję Zarządzaj pakietami NuGet dla rozwiązania.

    Zrzut ekranu przedstawiający menu Narzędzia umożliwiające rozpoczęcie walidacji trybu jQuery dla ustawień regionalnych innych niż angielskie.

  2. W okienku po lewej stronie wybierz pozycję Przeglądaj*. *(Zobacz poniższy obraz).

  3. W polu wejściowym wprowadź wartość Globalize*.

    Zrzut ekranu przedstawiający pole wejściowe, aby wprowadzić wartość Globalize.

    Wybierz jQuery.Validation.Globalizepozycję , wybierz i MvcMovie kliknij przycisk Zainstaluj. Plik Scripts\jquery.globalize\globalize.js zostanie dodany do projektu. Folder *Scripts\jquery.globalize\culture* będzie zawierać wiele plików języka JavaScript kultury. Pamiętaj, że zainstalowanie tego pakietu może potrwać pięć minut.

    Poniższy kod przedstawia modyfikacje pliku Views\Movies\Edit.cshtml:

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

<script src="~/Scripts/globalize/globalize.js"></script>
<script src="~/Scripts/globalize/cultures/globalize.culture.@(System.Threading.Thread.CurrentThread.CurrentCulture.Name).js"></script>
<script>
    $.validator.methods.number = function (value, element) {
        return this.optional(element) ||
            !isNaN(Globalize.parseFloat(value));
    }
    $(document).ready(function () {
        Globalize.culture('@(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
    });
</script>
<script>
    jQuery.extend(jQuery.validator.methods, {
        range: function (value, element, param) {
            //Use the Globalization plugin to parse the value
            var val = Globalize.parseFloat(value);
            return this.optional(element) || (
                val >= param[0] && val <= param[1]);
        }
    });
    $.validator.methods.date = function (value, element) {
        return this.optional(element) ||
            Globalize.parseDate(value) ||
            Globalize.parseDate(value, "yyyy-MM-dd");
    }
</script>
}

Aby uniknąć powtarzania tego kodu w każdym widoku edycji, możesz przenieść go do pliku układu. Aby zoptymalizować pobieranie skryptu, zobacz mój samouczek Bundling and Minification.

Aby uzyskać więcej informacji, zobacz ASP.NET MVC 3 Internationalization and ASP.NET MVC 3 Internationalization - Part 2 (NerdDinner).

W ramach tymczasowej poprawki, jeśli nie możesz uzyskać sprawdzania poprawności w ustawieniach regionalnych, możesz wymusić użycie języka angielskiego w stanach ZJEDNOCZONYCH lub wyłączyć język JavaScript w przeglądarce. Aby wymusić, aby komputer używał języka angielskiego w Stanach Zjednoczonych, możesz dodać element globalizacji do pliku głównegoweb.config projektów. Poniższy kod przedstawia element globalizacji z kulturą ustawioną na Stany Zjednoczone angielskiej.

<system.web>
    <globalization culture ="en-US" />
    <!--elements removed for clarity-->
  </system.web>

W następnym samouczku zaimplementujemy funkcje wyszukiwania.