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.
Link Edit został wygenerowany przez metodę Html.ActionLink
w widoku Views\Movies\Index.cshtml :
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
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.
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.
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).
W menu Narzędzia kliknij pozycję NuGet Menedżer pakietów, a następnie kliknij pozycję Zarządzaj pakietami NuGet dla rozwiązania.
W okienku po lewej stronie wybierz pozycję Przeglądaj*.*(Zobacz obraz poniżej).
W polu wejściowym wprowadź wartość Globalize*.
Wybierz pozycję
jQuery.Validation.Globalize
, aMvcMovie
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.