Udostępnij za pośrednictwem


Badanie metod i widoków akcji Edycji dla 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 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 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 adnotacje danych. 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 pomocnikiem, który jest uwidoczniony 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>). Drugi argument to 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 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. Zapoznaj się z poniższym kodem z pliku App_Start\RouteConfig.cs . Metoda MapRoute służy do kierowania żądań HTTP do poprawnego kontrolera i metody akcji oraz 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ż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). Atrybut Bind to kolejny ważny mechanizm zabezpieczeń, który chroni hakerów przed nadmiernym publikowaniem danych do modelu. Należy uwzględnić tylko właściwości w atrybucie powiązania, który chcesz zmienić. Więcej informacji na temat zastępowania i atrybutu powiązania można przeczytać w 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łszerzowania formularza, który musi być zgodny z Edit metodą Movies kontrolera. Więcej informacji o fałszerzowaniu żądań między witrynami (znanym również jako XSRF lub CSRF) można przeczytać w samouczku XSRF/CSRF Prevention in MVC (Zapobieganie żądaniom XSRF/CSRF).

Metoda HttpGet Edit pobiera parametr identyfikatora filmu, wyszukuje film przy użyciu metody Entity Framework Find i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, zwracany jest błąd HttpNotFound . 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 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 zawiera 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", "Gatunek" 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 na /Movies/Edit URL. 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 lub aktualizowania) Movie 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 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 i nie modyfikuje utrwalone dane.

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

Jeśli używasz komputera w języku angielskim(USA), możesz pominąć tę sekcję i przejść do następnego samouczka. Możesz pobrać wersję globalną tego samouczka tutaj. Aby zapoznać się z doskonałym dwuczęściowym samouczkiem dotyczącym internationalization, 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 przecinka dziesiętnego i formatów dat innych niż ANGIELSKI, należy uwzględnić globalize.js i określone kultury/globalize.cultures.js file(from https://github.com/jquery/globalize ) i JavaScript do użycia .Globalize.parseFloat Możesz uzyskać walidację w języku jQuery spoza języka angielskiego z narzędzia NuGet. (Nie instaluj globalizowania, jeśli używasz ustawień regionalnych w języku angielskim).

  1. W menu Narzędzia kliknij pozycję NuGet Menedżer pakietów, 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 zapytania jQuery dla ustawień regionalnych innych niż angielskie.

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

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

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

    Wybierz pozycję jQuery.Validation.Globalize, a MvcMovie następnie kliknij pozycję 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 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ć, aby komputer używał 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 głównego pliku web.config projektów. Poniższy kod przedstawia element globalizacji z kulturą ustawioną na Stany Zjednoczone angielski.

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

W następnym samouczku zaimplementujemy funkcje wyszukiwania.