Część 6, metody kontrolera i widoki w ASP.NET Core
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: Rick Anderson
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinna być dwoma słowami.
Models/Movie.cs
Otwórz plik i dodaj wyróżnione wiersze pokazane poniżej:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string? Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
DataAnnotations
objaśniono w następnym samouczku. 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 (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych jest wymagana [Column(TypeName = "decimal(18, 2)")]
, aby program Entity Framework Core mógł poprawnie mapować Price
na walutę w bazie danych. Aby uzyskać więcej informacji, zobacz Typy danych.
Przejdź do Movies
kontrolera i przytrzymaj wskaźnik myszy nad linkiem Edytuj , aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów Views/Movies/Index.cshtml
zakotwiczenia podstawowego MVC w pliku.
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
Pomocnicy tagów umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym AnchorTagHelper
kodzie dynamicznie generuje wartość atrybutu HTML href
z metody akcji kontrolera i identyfikator trasy. Użyjesz pozycji Wyświetl źródło z ulubionej przeglądarki lub użyjesz narzędzi deweloperskich do zbadania wygenerowanego znacznika. Poniżej przedstawiono część wygenerowanego kodu HTML:
<td>
<a href="/Movies/Edit/4"> Edit </a> |
<a href="/Movies/Details/4"> Details </a> |
<a href="/Movies/Delete/4"> Delete </a>
</td>
Przypomnij sobie format zestawu routingu Program.cs
w pliku:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core przekłada się https://localhost:5001/Movies/Edit/4
na żądanie do Edit
metody Movies
akcji kontrolera z parametrem Id
4. (Metody kontrolera są również nazywane metodami akcji).
Pomocnicy tagów są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Dodatkowe zasoby.
Movies
Otwórz kontroler i sprawdź dwie Edit
metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit
, która pobiera film i wypełnia formularz edycji Edit.cshtml
Razor wygenerowany przez plik.
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
Poniższy kod przedstawia metodę HTTP POST Edit
, która przetwarza opublikowane wartości filmu:
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [Bind]
jest jednym ze sposobów ochrony przed nadmiernym publikowaniem. Właściwości należy uwzględnić tylko w atrybucie [Bind]
, który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem. Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu delegowaniu.
Zwróć uwagę, że druga Edit
metoda akcji jest poprzedzona atrybutem [HttpPost]
.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut HttpPost
określa, że ta Edit
metoda może być wywoływana tylko dla POST
żądań. Atrybut można zastosować [HttpGet]
do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet]
jest to ustawienie domyślne.
Atrybut ValidateAntiForgeryToken
służy do zapobiegania fałszerzowaniu żądania i jest sparowany z tokenem antyforgery wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml
). Plik widoku edycji generuje token antyforgery za pomocą pomocnika tagów formularza.
<form asp-action="Edit">
Pomocnik tagów formularzy generuje ukryty token antyforgery, który musi być zgodny [ValidateAntiForgeryToken]
z wygenerowanym tokenem antyforgery w Edit
metodzie kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.
Metoda HttpGet Edit
pobiera parametr filmu ID
, wyszukuje film przy użyciu metody Entity Framework FindAsync
i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, NotFound
zostanie zwrócony (HTTP 404).
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
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
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Zwróć uwagę, że szablon widoku zawiera instrukcję @model MvcMovie.Models.Movie
w górnej części pliku. @model MvcMovie.Models.Movie
określa, że widok oczekuje, że model szablonu widoku będzie typu Movie
.
Kod szkieletowy używa kilku metod pomocnika tagów w celu usprawnienia znaczników HTML. Pomocnik tagów etykiet wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik tagów wejściowych renderuje element HTML<input>
. Pomocnik tagu weryfikacji wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.
Uruchom aplikację i przejdź do /Movies
adresu URL. Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Wygenerowany kod HTML dla <form>
elementu jest pokazany poniżej.
<form action="/Movies/Edit/7" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
<div class="text-danger" />
<input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
<div class="form-group">
<label class="control-label col-md-2" for="Genre" />
<div class="col-md-10">
<input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
<span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Price" />
<div class="col-md-10">
<input class="form-control" type="text" 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" value="3.99" />
<span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
</div>
<!-- Markup 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>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>
<input>
Elementy znajdują się w elemecieHTML <form>
, którego action
atrybut jest ustawiony na publikowanie w adresie /Movies/Edit/id
URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu Save
przycisku. Ostatni wiersz przed elementem zamykającym </form>
pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Na poniższej [HttpPost]
liście przedstawiono wersję Edit
metody akcji.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [ValidateAntiForgeryToken]
weryfikuje ukryty token XSRF wygenerowany przez generator tokenów antyforgery w Pomocnik tagu formularza
System powiązania modelu przyjmuje opublikowane wartości formularza i tworzy Movie
obiekt, który jest przekazywany jako movie
parametr. Właściwość 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, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie SaveChangesAsync
metody kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do Index
metody MoviesController
akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.
Przed opublikowaniem formularza na serwerze walidacja po stronie klienta sprawdza wszystkie reguły walidacji w polach. Jeśli wystąpią jakiekolwiek błędy walidacji, zostanie wyświetlony komunikat o błędzie i formularz nie zostanie opublikowany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe wartości opublikowane, a wartości formularza będą odtwarzane ponownie z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy weryfikację modelu. Pomocnik tagów weryfikacji w szablonie Views/Movies/Edit.cshtml
widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet
Wszystkie metody w kontrolerze filmu są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index
), i przekazują obiekt (model) do widoku. Metoda Create
przekazuje pusty obiekt filmu do Create
widoku. 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 HTTP GET
narusza również najlepsze rozwiązania HTTP i wzorzec architektury REST , 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.
Dodatkowe zasoby
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocnicy tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Pomocnik tagów etykiety
- Pomocnik tagów wyboru
- Pomocnik tagu weryfikacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinna być dwoma słowami.
Models/Movie.cs
Otwórz plik i dodaj wyróżnione wiersze pokazane poniżej:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string? Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
DataAnnotations
objaśniono w następnym samouczku. 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 (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych jest wymagana [Column(TypeName = "decimal(18, 2)")]
, aby program Entity Framework Core mógł poprawnie mapować Price
na walutę w bazie danych. Aby uzyskać więcej informacji, zobacz Typy danych.
Przejdź do Movies
kontrolera i przytrzymaj wskaźnik myszy nad linkiem Edytuj , aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów Views/Movies/Index.cshtml
zakotwiczenia podstawowego MVC w pliku.
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
Pomocnicy tagów umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym AnchorTagHelper
kodzie dynamicznie generuje wartość atrybutu HTML href
z metody akcji kontrolera i identyfikator trasy. Użyjesz pozycji Wyświetl źródło z ulubionej przeglądarki lub użyjesz narzędzi deweloperskich do zbadania wygenerowanego znacznika. Poniżej przedstawiono część wygenerowanego kodu HTML:
<td>
<a href="/Movies/Edit/4"> Edit </a> |
<a href="/Movies/Details/4"> Details </a> |
<a href="/Movies/Delete/4"> Delete </a>
</td>
Przypomnij sobie format zestawu routingu Program.cs
w pliku:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core przekłada się https://localhost:5001/Movies/Edit/4
na żądanie do Edit
metody Movies
akcji kontrolera z parametrem Id
4. (Metody kontrolera są również nazywane metodami akcji).
Pomocnicy tagów są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Dodatkowe zasoby.
Movies
Otwórz kontroler i sprawdź dwie Edit
metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit
, która pobiera film i wypełnia formularz edycji Edit.cshtml
Razor wygenerowany przez plik.
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
Poniższy kod przedstawia metodę HTTP POST Edit
, która przetwarza opublikowane wartości filmu:
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [Bind]
jest jednym ze sposobów ochrony przed nadmiernym publikowaniem. Właściwości należy uwzględnić tylko w atrybucie [Bind]
, który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem. Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu delegowaniu.
Zwróć uwagę, że druga Edit
metoda akcji jest poprzedzona atrybutem [HttpPost]
.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut HttpPost
określa, że ta Edit
metoda może być wywoływana tylko dla POST
żądań. Atrybut można zastosować [HttpGet]
do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet]
jest to ustawienie domyślne.
Atrybut ValidateAntiForgeryToken
służy do zapobiegania fałszerzowaniu żądania i jest sparowany z tokenem antyforgery wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml
). Plik widoku edycji generuje token antyforgery za pomocą pomocnika tagów formularza.
<form asp-action="Edit">
Pomocnik tagów formularzy generuje ukryty token antyforgery, który musi być zgodny [ValidateAntiForgeryToken]
z wygenerowanym tokenem antyforgery w Edit
metodzie kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.
Metoda HttpGet Edit
pobiera parametr filmu ID
, wyszukuje film przy użyciu metody Entity Framework FindAsync
i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, NotFound
zostanie zwrócony (HTTP 404).
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
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
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Zwróć uwagę, że szablon widoku zawiera instrukcję @model MvcMovie.Models.Movie
w górnej części pliku. @model MvcMovie.Models.Movie
określa, że widok oczekuje, że model szablonu widoku będzie typu Movie
.
Kod szkieletowy używa kilku metod pomocnika tagów w celu usprawnienia znaczników HTML. Pomocnik tagów etykiet wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik tagów wejściowych renderuje element HTML<input>
. Pomocnik tagu weryfikacji wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.
Uruchom aplikację i przejdź do /Movies
adresu URL. Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Wygenerowany kod HTML dla <form>
elementu jest pokazany poniżej.
<form action="/Movies/Edit/7" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
<div class="text-danger" />
<input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
<div class="form-group">
<label class="control-label col-md-2" for="Genre" />
<div class="col-md-10">
<input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
<span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Price" />
<div class="col-md-10">
<input class="form-control" type="text" 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" value="3.99" />
<span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
</div>
<!-- Markup 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>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>
<input>
Elementy znajdują się w elemecieHTML <form>
, którego action
atrybut jest ustawiony na publikowanie w adresie /Movies/Edit/id
URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu Save
przycisku. Ostatni wiersz przed elementem zamykającym </form>
pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Na poniższej [HttpPost]
liście przedstawiono wersję Edit
metody akcji.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [ValidateAntiForgeryToken]
weryfikuje ukryty token XSRF wygenerowany przez generator tokenów antyforgery w Pomocnik tagu formularza
System powiązania modelu przyjmuje opublikowane wartości formularza i tworzy Movie
obiekt, który jest przekazywany jako movie
parametr. Właściwość 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, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie SaveChangesAsync
metody kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do Index
metody MoviesController
akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.
Przed opublikowaniem formularza na serwerze walidacja po stronie klienta sprawdza wszystkie reguły walidacji w polach. Jeśli wystąpią jakiekolwiek błędy walidacji, zostanie wyświetlony komunikat o błędzie i formularz nie zostanie opublikowany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe wartości opublikowane, a wartości formularza będą odtwarzane ponownie z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy weryfikację modelu. Pomocnik tagów weryfikacji w szablonie Views/Movies/Edit.cshtml
widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet
Wszystkie metody w kontrolerze filmu są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index
), i przekazują obiekt (model) do widoku. Metoda Create
przekazuje pusty obiekt filmu do Create
widoku. 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 HTTP GET
narusza również najlepsze rozwiązania HTTP i wzorzec architektury REST , 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.
Dodatkowe zasoby
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocnicy tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Pomocnik tagów etykiety
- Pomocnik tagów wyboru
- Pomocnik tagu weryfikacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinna być dwoma słowami.
Models/Movie.cs
Otwórz plik i dodaj wyróżnione wiersze pokazane poniżej:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string? Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
DataAnnotations
objaśniono w następnym samouczku. 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 (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych jest wymagana [Column(TypeName = "decimal(18, 2)")]
, aby program Entity Framework Core mógł poprawnie mapować Price
na walutę w bazie danych. Aby uzyskać więcej informacji, zobacz Typy danych.
Przejdź do Movies
kontrolera i przytrzymaj wskaźnik myszy nad linkiem Edytuj , aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów Views/Movies/Index.cshtml
zakotwiczenia podstawowego MVC w pliku.
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
Pomocnicy tagów umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym AnchorTagHelper
kodzie dynamicznie generuje wartość atrybutu HTML href
z metody akcji kontrolera i identyfikator trasy. Użyjesz pozycji Wyświetl źródło z ulubionej przeglądarki lub użyjesz narzędzi deweloperskich do zbadania wygenerowanego znacznika. Poniżej przedstawiono część wygenerowanego kodu HTML:
<td>
<a href="/Movies/Edit/4"> Edit </a> |
<a href="/Movies/Details/4"> Details </a> |
<a href="/Movies/Delete/4"> Delete </a>
</td>
Przypomnij sobie format zestawu routingu Program.cs
w pliku:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core przekłada się https://localhost:5001/Movies/Edit/4
na żądanie do Edit
metody Movies
akcji kontrolera z parametrem Id
4. (Metody kontrolera są również nazywane metodami akcji).
Pomocnicy tagów są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Dodatkowe zasoby.
Movies
Otwórz kontroler i sprawdź dwie Edit
metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit
, która pobiera film i wypełnia formularz edycji Edit.cshtml
Razor wygenerowany przez plik.
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
Poniższy kod przedstawia metodę HTTP POST Edit
, która przetwarza opublikowane wartości filmu:
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [Bind]
jest jednym ze sposobów ochrony przed nadmiernym publikowaniem. Właściwości należy uwzględnić tylko w atrybucie [Bind]
, który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem. Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu delegowaniu.
Zwróć uwagę, że druga Edit
metoda akcji jest poprzedzona atrybutem [HttpPost]
.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut HttpPost
określa, że ta Edit
metoda może być wywoływana tylko dla POST
żądań. Atrybut można zastosować [HttpGet]
do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet]
jest to ustawienie domyślne.
Atrybut ValidateAntiForgeryToken
służy do zapobiegania fałszerzowaniu żądania i jest sparowany z tokenem antyforgery wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml
). Plik widoku edycji generuje token antyforgery za pomocą pomocnika tagów formularza.
<form asp-action="Edit">
Pomocnik tagów formularzy generuje ukryty token antyforgery, który musi być zgodny [ValidateAntiForgeryToken]
z wygenerowanym tokenem antyforgery w Edit
metodzie kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.
Metoda HttpGet Edit
pobiera parametr filmu ID
, wyszukuje film przy użyciu metody Entity Framework FindAsync
i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, NotFound
zostanie zwrócony (HTTP 404).
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
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
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Zwróć uwagę, że szablon widoku zawiera instrukcję @model MvcMovie.Models.Movie
w górnej części pliku. @model MvcMovie.Models.Movie
określa, że widok oczekuje, że model szablonu widoku będzie typu Movie
.
Kod szkieletowy używa kilku metod pomocnika tagów w celu usprawnienia znaczników HTML. Pomocnik tagów etykiet wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik tagów wejściowych renderuje element HTML<input>
. Pomocnik tagu weryfikacji wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.
Uruchom aplikację i przejdź do /Movies
adresu URL. Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Wygenerowany kod HTML dla <form>
elementu jest pokazany poniżej.
<form action="/Movies/Edit/7" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
<div class="text-danger" />
<input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
<div class="form-group">
<label class="control-label col-md-2" for="Genre" />
<div class="col-md-10">
<input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
<span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Price" />
<div class="col-md-10">
<input class="form-control" type="text" 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" value="3.99" />
<span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
</div>
<!-- Markup 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>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>
<input>
Elementy znajdują się w elemecieHTML <form>
, którego action
atrybut jest ustawiony na publikowanie w adresie /Movies/Edit/id
URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu Save
przycisku. Ostatni wiersz przed elementem zamykającym </form>
pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Na poniższej [HttpPost]
liście przedstawiono wersję Edit
metody akcji.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [ValidateAntiForgeryToken]
weryfikuje ukryty token XSRF wygenerowany przez generator tokenów antyforgery w Pomocnik tagu formularza
System powiązania modelu przyjmuje opublikowane wartości formularza i tworzy Movie
obiekt, który jest przekazywany jako movie
parametr. Właściwość 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, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie SaveChangesAsync
metody kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do Index
metody MoviesController
akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.
Przed opublikowaniem formularza na serwerze walidacja po stronie klienta sprawdza wszystkie reguły walidacji w polach. Jeśli wystąpią jakiekolwiek błędy walidacji, zostanie wyświetlony komunikat o błędzie i formularz nie zostanie opublikowany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe wartości opublikowane, a wartości formularza będą odtwarzane ponownie z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy weryfikację modelu. Pomocnik tagów weryfikacji w szablonie Views/Movies/Edit.cshtml
widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet
Wszystkie metody w kontrolerze filmu są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index
), i przekazują obiekt (model) do widoku. Metoda Create
przekazuje pusty obiekt filmu do Create
widoku. 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 HTTP GET
narusza również najlepsze rozwiązania HTTP i wzorzec architektury REST , 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.
Dodatkowe zasoby
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocnicy tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Pomocnik tagów etykiety
- Pomocnik tagów wyboru
- Pomocnik tagu weryfikacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinna być dwoma słowami.
Models/Movie.cs
Otwórz plik i dodaj wyróżnione wiersze pokazane poniżej:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string? Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
DataAnnotations
objaśniono w następnym samouczku. 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 (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych jest wymagana [Column(TypeName = "decimal(18, 2)")]
, aby program Entity Framework Core mógł poprawnie mapować Price
na walutę w bazie danych. Aby uzyskać więcej informacji, zobacz Typy danych.
Przejdź do Movies
kontrolera i przytrzymaj wskaźnik myszy nad linkiem Edytuj , aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów Views/Movies/Index.cshtml
zakotwiczenia podstawowego MVC w pliku.
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
Pomocnicy tagów umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym AnchorTagHelper
kodzie dynamicznie generuje wartość atrybutu HTML href
z metody akcji kontrolera i identyfikator trasy. Użyjesz pozycji Wyświetl źródło z ulubionej przeglądarki lub użyjesz narzędzi deweloperskich do zbadania wygenerowanego znacznika. Poniżej przedstawiono część wygenerowanego kodu HTML:
<td>
<a href="/Movies/Edit/4"> Edit </a> |
<a href="/Movies/Details/4"> Details </a> |
<a href="/Movies/Delete/4"> Delete </a>
</td>
Przypomnij sobie format zestawu routingu Program.cs
w pliku:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core przekłada się https://localhost:5001/Movies/Edit/4
na żądanie do Edit
metody Movies
akcji kontrolera z parametrem Id
4. (Metody kontrolera są również nazywane metodami akcji).
Pomocnicy tagów są popularną funkcją w ASP.NET Core. Aby uzyskać więcej informacji na ich temat, zobacz Dodatkowe zasoby.
Movies
Otwórz kontroler i sprawdź dwie Edit
metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit
, która pobiera film i wypełnia formularz edycji Edit.cshtml
Razor wygenerowany przez plik.
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
Poniższy kod przedstawia metodę HTTP POST Edit
, która przetwarza opublikowane wartości filmu:
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [Bind]
jest jednym ze sposobów ochrony przed nadmiernym publikowaniem. Właściwości należy uwzględnić tylko w atrybucie [Bind]
, który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem. Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu delegowaniu.
Zwróć uwagę, że druga Edit
metoda akcji jest poprzedzona atrybutem [HttpPost]
.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut HttpPost
określa, że ta Edit
metoda może być wywoływana tylko dla POST
żądań. Atrybut można zastosować [HttpGet]
do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet]
jest to ustawienie domyślne.
Atrybut ValidateAntiForgeryToken
służy do zapobiegania fałszerzowaniu żądania i jest sparowany z tokenem antyforgery wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml
). Plik widoku edycji generuje token antyforgery za pomocą pomocnika tagów formularza.
<form asp-action="Edit">
Pomocnik tagów formularzy generuje ukryty token antyforgery, który musi być zgodny [ValidateAntiForgeryToken]
z wygenerowanym tokenem antyforgery w Edit
metodzie kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.
Metoda HttpGet Edit
pobiera parametr filmu ID
, wyszukuje film przy użyciu metody Entity Framework FindAsync
i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, NotFound
zostanie zwrócony (HTTP 404).
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
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
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Zwróć uwagę, że szablon widoku zawiera instrukcję @model MvcMovie.Models.Movie
w górnej części pliku. @model MvcMovie.Models.Movie
określa, że widok oczekuje, że model szablonu widoku będzie typu Movie
.
Kod szkieletowy używa kilku metod pomocnika tagów w celu usprawnienia znaczników HTML. Pomocnik tagów etykiet wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik tagów wejściowych renderuje element HTML<input>
. Pomocnik tagu weryfikacji wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.
Uruchom aplikację i przejdź do /Movies
adresu URL. Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Wygenerowany kod HTML dla <form>
elementu jest pokazany poniżej.
<form action="/Movies/Edit/7" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
<div class="text-danger" />
<input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
<div class="form-group">
<label class="control-label col-md-2" for="Genre" />
<div class="col-md-10">
<input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
<span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Price" />
<div class="col-md-10">
<input class="form-control" type="text" 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" value="3.99" />
<span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
</div>
<!-- Markup 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>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>
<input>
Elementy znajdują się w elemecieHTML <form>
, którego action
atrybut jest ustawiony na publikowanie w adresie /Movies/Edit/id
URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu Save
przycisku. Ostatni wiersz przed elementem zamykającym </form>
pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Na poniższej [HttpPost]
liście przedstawiono wersję Edit
metody akcji.
// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (id != movie.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [ValidateAntiForgeryToken]
weryfikuje ukryty token XSRF wygenerowany przez generator tokenów antyforgery w Pomocnik tagu formularza
System powiązania modelu przyjmuje opublikowane wartości formularza i tworzy Movie
obiekt, który jest przekazywany jako movie
parametr. Właściwość 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, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie SaveChangesAsync
metody kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do Index
metody MoviesController
akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.
Przed opublikowaniem formularza na serwerze walidacja po stronie klienta sprawdza wszystkie reguły walidacji w polach. Jeśli wystąpią jakiekolwiek błędy walidacji, zostanie wyświetlony komunikat o błędzie i formularz nie zostanie opublikowany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe wartości opublikowane, a wartości formularza będą odtwarzane ponownie z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy weryfikację modelu. Pomocnik tagów weryfikacji w szablonie Views/Movies/Edit.cshtml
widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet
Wszystkie metody w kontrolerze filmu są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index
), i przekazują obiekt (model) do widoku. Metoda Create
przekazuje pusty obiekt filmu do Create
widoku. 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 HTTP GET
narusza również najlepsze rozwiązania HTTP i wzorzec architektury REST , 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.
Dodatkowe zasoby
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocnicy tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Pomocnik tagów etykiety
- Pomocnik tagów wyboru
- Pomocnik tagu weryfikacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinna być dwoma słowami.
Models/Movie.cs
Otwórz plik i dodaj wyróżnione wiersze pokazane poniżej:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
W następnym samouczku omówiono 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 (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych jest wymagana [Column(TypeName = "decimal(18, 2)")]
, aby program Entity Framework Core mógł poprawnie mapować Price
na walutę w bazie danych. Aby uzyskać więcej informacji, zobacz Typy danych.
Przejdź do Movies
kontrolera i przytrzymaj wskaźnik myszy nad linkiem Edytuj , aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów Views/Movies/Index.cshtml
zakotwiczenia podstawowego MVC w pliku.
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
Pomocnicy tagów umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym AnchorTagHelper
kodzie dynamicznie generuje wartość atrybutu HTML href
z metody akcji kontrolera i identyfikator trasy. Użyjesz pozycji Wyświetl źródło z ulubionej przeglądarki lub użyjesz narzędzi deweloperskich do zbadania wygenerowanego znacznika. Poniżej przedstawiono część wygenerowanego kodu HTML:
<td>
<a href="/Movies/Edit/4"> Edit </a> |
<a href="/Movies/Details/4"> Details </a> |
<a href="/Movies/Delete/4"> Delete </a>
</td>
Przypomnij sobie format zestawu routingu Startup.cs
w pliku:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
ASP.NET Core przekłada się https://localhost:5001/Movies/Edit/4
na żądanie do Edit
metody Movies
akcji kontrolera z parametrem Id
4. (Metody kontrolera są również nazywane metodami akcji).
Aby uzyskać więcej informacji na temat pomocników tagów, zobacz Dodatkowe zasoby.
Movies
Otwórz kontroler i sprawdź dwie Edit
metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit
, która pobiera film i wypełnia formularz edycji Edit.cshtml
Razor wygenerowany przez plik.
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
Poniższy kod przedstawia metodę HTTP POST Edit
, która przetwarza opublikowane wartości filmu:
// POST: Movies/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (id != movie.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("Index");
}
return View(movie);
}
Atrybut [Bind]
jest jednym ze sposobów ochrony przed nadmiernym publikowaniem. Właściwości należy uwzględnić tylko w atrybucie [Bind]
, który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem. Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu delegowaniu.
Zwróć uwagę, że druga Edit
metoda akcji jest poprzedzona atrybutem [HttpPost]
.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (id != movie.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut HttpPost
określa, że ta Edit
metoda może być wywoływana tylko dla POST
żądań. Atrybut można zastosować [HttpGet]
do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet]
jest to ustawienie domyślne.
Atrybut ValidateAntiForgeryToken
służy do zapobiegania fałszerzowaniu żądania i jest sparowany z tokenem antyforgery wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml
). Plik widoku edycji generuje token antyforgery za pomocą pomocnika tagów formularza.
<form asp-action="Edit">
Pomocnik tagów formularzy generuje ukryty token antyforgery, który musi być zgodny [ValidateAntiForgeryToken]
z wygenerowanym tokenem antyforgery w Edit
metodzie kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.
Metoda HttpGet Edit
pobiera parametr filmu ID
, wyszukuje film przy użyciu metody Entity Framework FindAsync
i zwraca wybrany film do widoku Edytuj. Jeśli nie można odnaleźć filmu, NotFound
zostanie zwrócony (HTTP 404).
// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FindAsync(id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
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
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Zwróć uwagę, że szablon widoku zawiera instrukcję @model MvcMovie.Models.Movie
w górnej części pliku. @model MvcMovie.Models.Movie
określa, że widok oczekuje, że model szablonu widoku będzie typu Movie
.
Kod szkieletowy używa kilku metod pomocnika tagów w celu usprawnienia znaczników HTML. Pomocnik tagów etykiet wyświetla nazwę pola ("Title", "ReleaseDate", "Gatunek" lub "Price"). Pomocnik tagów wejściowych renderuje element HTML<input>
. Pomocnik tagu weryfikacji wyświetla wszystkie komunikaty sprawdzania poprawności skojarzone z tą właściwością.
Uruchom aplikację i przejdź do /Movies
adresu URL. Kliknij link Edytuj. W przeglądarce wyświetl źródło strony. Wygenerowany kod HTML dla <form>
elementu jest pokazany poniżej.
<form action="/Movies/Edit/7" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
<div class="text-danger" />
<input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
<div class="form-group">
<label class="control-label col-md-2" for="Genre" />
<div class="col-md-10">
<input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
<span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Price" />
<div class="col-md-10">
<input class="form-control" type="text" 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" value="3.99" />
<span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
</div>
<!-- Markup 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>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>
<input>
Elementy znajdują się w elemecieHTML <form>
, którego action
atrybut jest ustawiony na publikowanie w adresie /Movies/Edit/id
URL. Dane formularza zostaną opublikowane na serwerze po kliknięciu Save
przycisku. Ostatni wiersz przed elementem zamykającym </form>
pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Na poniższej [HttpPost]
liście przedstawiono wersję Edit
metody akcji.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (id != movie.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(movie);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(movie);
}
Atrybut [ValidateAntiForgeryToken]
weryfikuje ukryty token XSRF wygenerowany przez generator tokenów antyforgery w Pomocnik tagu formularza
System powiązania modelu przyjmuje opublikowane wartości formularza i tworzy Movie
obiekt, który jest przekazywany jako movie
parametr. Właściwość 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, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie SaveChangesAsync
metody kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do Index
metody MoviesController
akcji klasy , która wyświetla kolekcję filmów, w tym wprowadzone zmiany.
Przed opublikowaniem formularza na serwerze walidacja po stronie klienta sprawdza wszystkie reguły walidacji w polach. Jeśli wystąpią jakiekolwiek błędy walidacji, zostanie wyświetlony komunikat o błędzie i formularz nie zostanie opublikowany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe wartości opublikowane, a wartości formularza będą odtwarzane ponownie z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy weryfikację modelu. Pomocnik tagów weryfikacji w szablonie Views/Movies/Edit.cshtml
widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet
Wszystkie metody w kontrolerze filmu są zgodne z podobnym wzorcem. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index
), i przekazują obiekt (model) do widoku. Metoda Create
przekazuje pusty obiekt filmu do Create
widoku. 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 HTTP GET
narusza również najlepsze rozwiązania HTTP i wzorzec architektury REST , 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.
Dodatkowe zasoby
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocnicy tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Pomocnik tagów etykiety
- Pomocnik tagów wyboru
- Pomocnik tagu weryfikacji