Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Notatka
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz Zasady pomocy technicznej dla platform .NET i .NET Core. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinno być wyświetlane jako dwa słowa.
Otwórz plik Models/Movie.cs 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 zostały objaśnione w następnym samouczku. Atrybut Display określa, co ma być wyświetlane dla nazwy pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych (Data).
Korzystając z powyższych adnotacji danych, uruchom aplikację i odśwież /Movies stronę. Ponieważ znaczniki widoku używają metod @Html.DisplayNameFor i @Html.DisplayFor do renderowania nazwy i wartości właściwości, zaktualizowany widok Index pokazuje wszystkie pola prawidłowo sformatowane. Na przykład data wydania to teraz dwa wyrazy.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] jest wymagana, 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.
Linki Edytuj, Szczegóły i Usuń są generowane przez pomocnik tagów Anchor w ASP.NET Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers 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 routingu ustawiony w pliku Program.cs:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
.WithStaticAssets();
ASP.NET Core mapuje https://localhost:5001/Movies/Edit/4 na żądanie do metody akcji Edit kontrolera Movies z parametrem Id o wartości 4. (Metody kontrolera są również nazywane metodami akcji).
Tag Helpers są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Powiązana zawartość.
Movies Otwórz kontroler i sprawdź dwie Edit metody działania. Poniższy kod pokazuje metodę HTTP GET Edit, która pobiera film i wypełnia formularz edycji wygenerowany przez plik Edit.cshtmlRazor.
// 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 over-postingiem. Właściwości należy uwzględnić tylko w atrybucie [Bind] , który chcesz zmienić. Aby uzyskać więcej informacji, zobacz Chroń kontroler przed nadmiernym publikowaniem.
ViewModels stanowią alternatywną metodę zapobiegania nadmiernemu przesyłaniu danych.
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 w przypadku żądań POST. Atrybut [HttpGet] można zastosować do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet] jest ustawieniem domyślnym.
Atrybut ValidateAntiForgeryToken służy do zapobiegania sfałszowaniu żądania i jest powiązany z tokenem zabezpieczającym przed fałszerstwem wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml). Plik widoku edycji generuje token zapobiegający fałszerstwom żądań za pomocą Form Tag Helper.
<form asp-action="Edit">
pomocnik tagów formularza generuje ukryty token zapobiegający fałszerstwom, który musi być zgodny z tokenem zapobiegającym fałszerstwom wygenerowanym [ValidateAntiForgeryToken] w metodzie Edit kontrolera Filmy. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom typu fałszowanie żądań między witrynami (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, zwracany jest komunikat NotFound (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 scaffolding 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 wygenerowany przez scaffolding używa kilku metod Tag Helper w celu usprawnienia znaczników HTML.
Label Tag Helper wyświetla nazwę pola („Title”, „ReleaseDate”, „Genre” lub „Price”).
Pomocnik tagów Input renderuje element HTML <input>.
Tag Helper walidacji 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>
Elementy <input> znajdują się w elemencie HTML <form>, którego atrybut action jest ustawiony na wysyłanie pod adres URL /Movies/Edit/id. Dane formularza zostaną wysłane do serwera po kliknięciu przycisku Save. Ostatni wiersz przed elementem zamykającym </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów Form.
Przetwarzanie żądania POST
W poniższym [HttpPost] listingu 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 pomocniku tagów Form
system wiązania modelu przyjmuje przesłane 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 metody SaveChangesAsync kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, w tym właśnie wprowadzone zmiany.
Przed wysłaniem formularza na serwer 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 wysłany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe przesłane wartości, a wartości formularza zostaną ponownie wyświetlone z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo omówimy walidację modelu.
Pomocnik tagów Validation w szablonie widoku Views/Movies/Edit.cshtml zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
Wszystkie metody w kontrolerze filmu HttpGet mają podobny schemat. 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, odbywa się to w przeciążonej wersji metody [HttpPost]. Modyfikowanie danych w metodzie oznaczonej przez 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 utrwalonych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocniki tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym przypisywaniem
- Modele widoków
- Pomocnik tagów formularzy
- Pomocnik tagów input
- Label Tag Helper
- Pomocnik tagów Select
- Tag Helper walidacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinno być wyświetlane jako dwa słowa.
Otwórz plik Models/Movie.cs 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 zostały objaśnione w następnym samouczku. Atrybut Display określa, co ma być wyświetlane dla nazwy pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Korzystając z powyższych adnotacji danych, uruchom aplikację i odśwież /Movies stronę. Ponieważ znaczniki widoku używają metod @Html.DisplayNameFor i @Html.DisplayFor do renderowania nazwy i wartości właściwości, zaktualizowany widok Index pokazuje wszystkie pola prawidłowo sformatowane. Na przykład data wydania to teraz dwa wyrazy, a informacje o czasie nie są już wyświetlane.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] jest wymagana, 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.
Linki Edytuj, Szczegóły i Usuń są generowane przez pomocnik tagów Anchor w ASP.NET Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym kodzie element AnchorTagHelper dynamicznie generuje wartość atrybutu HTML href na podstawie metody akcji kontrolera i identyfikatora trasy. Możesz użyć pozycji Wyświetl źródło w swojej ulubionej przeglądarce lub narzędzi deweloperskich, aby zbadać wygenerowany kod. 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 routingu ustawiony w pliku Program.cs:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core mapuje https://localhost:5001/Movies/Edit/4 na żądanie do metody akcji Edit kontrolera Movies z parametrem Id o wartości 4. (Metody kontrolera są również nazywane metodami akcji).
Tag Helpers są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Powiązana zawartość.
Movies Otwórz kontroler i sprawdź dwie Edit metody akcji. Poniższy kod pokazuje metodę HTTP GET Edit, która pobiera film i wypełnia formularz edycji wygenerowany przez plik Edit.cshtmlRazor.
// 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.
ViewModels stanowią alternatywną metodę zapobiegania nadmiernemu przesyłaniu danych.
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 w przypadku żądań POST. Atrybut [HttpGet] można zastosować do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet] jest ustawieniem domyślnym.
Atrybut ValidateAntiForgeryToken służy do zapobiegania sfałszowaniu żądania i jest powiązany z tokenem zabezpieczającym przed fałszerstwem wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml). Plik widoku edycji generuje token zapobiegający fałszerstwom żądań za pomocą Form Tag Helper.
<form asp-action="Edit">
pomocnik tagów formularza generuje ukryty token zapobiegający fałszerstwom, który musi być zgodny z tokenem zapobiegającym fałszerstwom wygenerowanym [ValidateAntiForgeryToken] w metodzie Edit 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, zwracany jest komunikat NotFound (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 scaffolding 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 wygenerowany przez scaffolding używa kilku metod Tag Helper w celu usprawnienia znaczników HTML.
Label Tag Helper wyświetla nazwę pola („Title”, „ReleaseDate”, „Genre” lub „Price”).
Pomocnik tagów Input renderuje element HTML <input>.
Tag Helper walidacji 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ą wysłane do serwera po kliknięciu przycisku Save. Ostatni wiersz przed elementem zamykającym </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularza.
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 zapobiegających fałszerstwom żądań w pomocniku tagów 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 weryfikuje, czy dane przesłane w formularzu mogą służyć do modyfikowania (edytowania lub aktualizowania) obiektu Movie. 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 metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, w tym wprowadzone właśnie zmiany.
Przed wysłaniem formularza do serwera 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 wysłany. Jeśli język JavaScript jest wyłączony, nie będzie dostępna walidacja po stronie klienta, ale serwer wykryje przesłane wartości, które są nieprawidłowe, a wartości formularza zostaną ponownie wyświetlone z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo omówimy walidację modelu.
Pomocnik tagów walidacji w szablonie widoku Views/Movies/Edit.cshtml 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, są wykonywane w przeciążeniu metody [HttpPost]. Modyfikowanie danych w HTTP GETmetodzie 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ć operacją bezpieczną, która nie ma skutków ubocznych i nie modyfikuje utrwalonych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Tag Helpers autora
- Zapobieganie atakom polegającym na fałszowaniu żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed over-postingiem
- Modele widoku
- Pomocnik tagów Form
- Pomocnik tagu input
- Pomocnik tagów Label
- Select Tag Helper
- Pomocnik tagów walidacji
Aplikacja filmowa ma już dobry początek, ale prezentacja nie jest idealna, na przykład ReleaseDate powinny być dwoma słowami.
Otwórz plik Models/Movie.cs 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 Display określa, jaka nazwa ma być wyświetlana dla pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych („Data”), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] jest wymagana, 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 kotwicy Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym kodzie element AnchorTagHelper dynamicznie generuje wartość atrybutu HTML href z metody akcji kontrolera i identyfikatora trasy. Możesz użyć pozycji Wyświetl źródło w ulubionej przeglądarce lub 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 routingu ustawiony w pliku Program.cs:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core mapuje https://localhost:5001/Movies/Edit/4 na żądanie do metody akcji Edit kontrolera Movies z parametrem Id o wartości 4. (Metody kontrolera są również nazywane metodami akcji).
Tag Helpers są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Powiązana zawartość.
Otwórz kontroler Movies i sprawdź dwie Edit metody akcji. Poniższy kod przedstawia metodę HTTP GET Edit, która pobiera film i wypełnia formularz edycji wygenerowany przez plik Edit.cshtmlRazor.
// 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 przesłane 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 over-postingiem. W atrybucie [Bind] należy uwzględnić tylko te właściwości, które chcesz zmienić. Aby uzyskać więcej informacji, zobacz Chroń kontroler przed nadmiernym publikowaniem.
Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu przesyłaniu danych.
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 w przypadku żądań POST. Można zastosować atrybut [HttpGet] do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet] jest ustawieniem domyślnym.
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 Form.
<form asp-action="Edit">
Pomocnik tagu Form generuje ukryty token antyfałszywkowy, który musi odpowiadać tokenowi antyfałszywkowemu wygenerowanemu [ValidateAntiForgeryToken] w metodzie Edit kontrolera Movies. 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, zwracany jest kod NotFound (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 scaffoldingu 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 model używany przez szablon widoku jest typu Movie.
Wygenerowany kod używa kilku metod Tag Helper, aby uprościć kod HTML.
Pomocnik tagów Label wyświetla nazwę pola („Title”, „ReleaseDate”, „Genre” lub „Price”).
Input Tag Helper generuje element HTML <input>.
Pomocnik tagów walidacji 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>
Elementy <input> znajdują się w elemencie HTML <form>, którego atrybut action jest ustawiony tak, aby wysyłać dane do adresu URL /Movies/Edit/id. Dane formularza zostaną wysłane na serwer po kliknięciu przycisku Save. Ostatni wiersz przed zamykającym znacznikiem </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów Form Tag Helper.
Przetwarzanie żądania POST
W poniższym [HttpPost] listingu 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 zapobiegających fałszerstwom żądań w pomocniku tagów formularza
system wiązania modelu przyjmuje przesłane wartości formularza i tworzy Movie obiekt, który jest przekazywany jako movie parametr. Właściwość ModelState.IsValid weryfikuje, czy dane przesłane w formularzu mogą służyć do modyfikowania (edytowania lub aktualizowania) obiektu Movie. Jeśli dane są prawidłowe, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie metody SaveChangesAsync kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, w tym wprowadzone właśnie zmiany.
Przed wysłaniem formularza do serwera 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 wysłany. Jeśli język JavaScript jest wyłączony, nie będzie dostępna walidacja po stronie klienta, ale serwer wykryje przesłane wartości, które są nieprawidłowe, a wartości formularza zostaną ponownie wyświetlone z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo omówimy walidację modelu.
Pomocnik tagów walidacji w szablonie widoku Views/Movies/Edit.cshtml zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
Wszystkie metody HttpGet w kontrolerze filmu mają podobny schemat. Pobierają obiekt filmu (lub listę obiektów, w przypadku Index), i przekazują obiekt (model) do widoku. Metoda Create przekazuje pusty obiekt Movie do widoku Create. Wszystkie metody, które tworzą, edytują, usuwają lub w inny sposób modyfikują dane, wykonują te operacje w przeciążeniu [HttpPost] danej metody. Modyfikowanie danych w metodzie HTTP GET stanowi zagrożenie 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 utrwalonych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do Tag Helpers
- Pomocniki tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Chroń swój kontroler przed nadmiernym publikowaniem
- Modele widoków
- Pomocnik tagu formularza
- Pomocnik tagów Input
- Label Tag Helper
- Wybór tagu Helper
- Validation Tag Helper
Mamy dobry początek aplikacji filmowej, ale sposób prezentacji nie jest idealny; na przykład ReleaseDate powinno składać się z dwóch słów.
Otwórz plik Models/Movie.cs 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 są objaśnione w następnym samouczku. Atrybut Display określa, co ma być wyświetlane jako nazwa pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] jest wymagana, 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 kontrolera Movies i najedź wskaźnikiem myszy na łącze Edytuj, aby wyświetlić docelowy adres URL.
Linki Edytuj, Szczegóły i Usuń są generowane przez pomocnik tagów kotwicy platformy Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers 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 routingu ustawiony w pliku Program.cs:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core tłumaczy https://localhost:5001/Movies/Edit/4 na żądanie do metody akcji Edit kontrolera Movies z parametrem Id o wartości 4. (Metody kontrolera są również nazywane metodami akcji).
Pomocnicy znaczników są jedną z najpopularniejszych nowych funkcji w ASP.NET Core. Aby uzyskać więcej informacji, zobacz Powiązana zawartość.
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 wygenerowany przez plik Edit.cshtmlRazor.
// 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 przesyłaniem danych. W atrybucie [Bind] należy uwzględniać tylko te właściwości, które chcesz zmienić. Aby uzyskać więcej informacji, zobacz Chroń kontroler przed nadmiernym publikowaniem.
ViewModels stanowią alternatywną metodę zapobiegania nadmiernemu przesyłaniu danych.
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 w przypadku 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 formularza Form Tag Helper generuje ukryty token ochrony przed fałszerstwami, który musi odpowiadać tokenowi ochrony przed fałszerstwami wygenerowanemu przez element [ValidateAntiForgeryToken] w metodzie Edit kontrolera Movies. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom polegającym na fałszowaniu żądań między witrynami (XSRF/CSRF) w 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 scaffoldingu 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 model używany przez szablon widoku jest typu Movie.
Wygenerowany kod używa kilku metod Tag Helper, aby uprościć kod HTML.
Pomocnik tagów Label wyświetla nazwę pola („Title”, „ReleaseDate”, „Genre” lub „Price”).
Input Tag Helper generuje element HTML <input>.
Pomocnik tagów walidacji 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ą wysłane na serwer po kliknięciu przycisku Save. Ostatni wiersz przed elementem zamykającym </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularzy.
Przetwarzanie żądania POST
Poniższy [HttpPost] wykaz pokazuje wersję Edit metody obsługi 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 wią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ą zostać użyte do zmodyfikowania (edytowania lub zaktualizowania) obiektu Movie. Jeśli dane są prawidłowe, są zapisywane. Zaktualizowane (zmodyfikowane) dane filmu zostają zapisane w bazie danych przez wywołanie metody SaveChangesAsync kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, łącznie z właśnie wprowadzonymi zmianami.
Przed wysłaniem formularza na serwer 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, a formularz nie zostanie wysłany. Jeśli obsługa JavaScript jest wyłączona, walidacja po stronie klienta nie będzie działać, ale serwer wykryje nieprawidłowe przesłane wartości, a wartości formularza zostaną ponownie wyświetlone wraz z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo sprawdzimy walidację modelu.
Pomocnik tagów Validation w szablonie Views/Movies/Edit.cshtml widoku zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
HttpGet Wszystkie metody w kontrolerze movie 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 movie do widoku Create. Wszystkie metody, które tworzą, edytują, usuwają lub w inny sposób modyfikują dane, odbywa się to w przeciążeniu metody [HttpPost]. 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 trwale zapisanych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Tag Helpers autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Chroń kontroler przed over-postingiem
- Modele widoków
- Pomocnik tagów formularza
- Input Tag Helper
- Pomocnik tagu Label
- Tag Helper Select
- Pomocnik tagów walidacji
Mamy dobry początek aplikacji filmowej, ale sposób prezentacji nie jest idealny, na przykład ReleaseDate powinno składać się z dwóch słów.
Otwórz plik Models/Movie.cs 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 Display określa, co ma być wyświetlane dla nazwy pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] jest wymagana, 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 kontrolera Movies i najedź kursorem na łącze Edytuj, aby wyświetlić docelowy adres URL.
Łącza Edytuj, Szczegóły i Usuń są generowane przez pomocnika tagów kotwicy platformy Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym kodzie atrybut AnchorTagHelper dynamicznie generuje wartość atrybutu HTML href z metody akcji kontrolera i identyfikatora trasy. Użyj pozycji Wyświetl źródło w ulubionej przeglądarce lub narzędzi deweloperskich, aby zbadać wygenerowany znacznik. 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 routingu ustawionego w pliku Program.cs:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
ASP.NET Core mapuje https://localhost:5001/Movies/Edit/4 na żądanie do metody akcji Edit kontrolera Movies z parametrem Id o wartości 4. (Metody kontrolera są również nazywane metodami akcji).
Tag Helpers są popularną funkcją w ASP.NET Core. Aby uzyskać więcej informacji na ich temat, zobacz Powiązana zawartość.
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.cshtmlRazor 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 przesłane 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 over-postingiem. Właściwości należy uwzględnić tylko w atrybucie [Bind], które chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem.
Modely ViewModel stanowią alternatywną metodę zapobiegania nadmiernemu przesyłaniu danych.
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 w przypadku POST żądań. Można zastosować atrybut [HttpGet] do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet] jest ustawieniem domyślnym.
Atrybut ValidateAntiForgeryToken służy do zapobiegania sfałszowaniu żądania i jest powiązany z tokenem zapobiegającym fałszerstwom wygenerowanym w pliku widoku edycji (Views/Movies/Edit.cshtml). Plik widoku edycji generuje token zabezpieczający przed fałszerstwem żądań za pomocą składnika Form Tag Helper.
<form asp-action="Edit">
Pomocnik tagów formularza generuje ukryty token przeciwfałszeniowy, który musi odpowiadać tokenowi przeciwfałszeniowemu wygenerowanemu przez metodę Edit kontrolera Filmy [ValidateAntiForgeryToken]. Aby uzyskać więcej informacji, zobacz Zapobieganie atakom polegającym na fałszowaniu żądań między witrynami (XSRF/CSRF) w programie ASP.NET Core.
Metoda HttpGet Edit przyjmuje parametr filmu ID, wyszukuje film za pomocą metody FindAsync platformy Entity Framework i zwraca wybrany film do widoku Edit. Jeśli nie można odnaleźć filmu, zwracany jest NotFound (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 na początku pliku.
@model MvcMovie.Models.Movie określa, że widok oczekuje, że model szablonu widoku będzie typu Movie.
Kod wygenerowany przez rusztowanie używa kilku metod Tag Helpera w celu usprawnienia znaczników HTML.
Pomocnik tagów Label wyświetla nazwę pola ("Title", "ReleaseDate", "Genre" lub "Price").
Pomocnik tagów wejściowych renderuje element HTML<input>.
Pomocnik tagów walidacji 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. 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>
Elementy <input> znajdują się w elemencie HTML <form>, którego atrybut action jest ustawiony tak, aby wysyłać do adresu URL /Movies/Edit/id. Dane formularza zostaną wysłane do serwera po kliknięciu przycisku Save. Ostatni wiersz przed elementem zamykającym </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów Form.
Przetwarzanie żądania POST
W poniższym [HttpPost] zestawieniu przedstawiono wersję Edit metody action.
// 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 pomocniku tagów Form
system wiązania modelu przyjmuje przesłane 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 metody SaveChangesAsync kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, w tym właśnie wprowadzone zmiany.
Przed wysłaniem formularza na serwer 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 wysłany. Jeśli język JavaScript jest wyłączony, nie będziesz mieć weryfikacji po stronie klienta, ale serwer wykryje nieprawidłowe przesłane wartości, a wartości formularza zostaną ponownie wyświetlone z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo omówimy walidację modelu.
Pomocnik tagów Validation w szablonie widoku Views/Movies/Edit.cshtml 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 przeciążonej wersji metody [HttpPost]. Modyfikowanie danych w metodzie HTTP GET stanowi zagrożenie dla 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 utrwalonych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Tag Helpers autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym wiązaniem danych
- ViewModele
- Pomocnik tagów formularza
- Pomocnik tagów danych wejściowych
- Label Tag Helper
- Select Tag Helper
- Pomocnik tagu weryfikacji
Mamy dobry początek aplikacji filmowej, ale prezentacja nie jest idealna, na przykład ReleaseDate powinno składać się z dwóch słów.
Otwórz plik Models/Movie.cs 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 DataAnnotations. Atrybut Display określa, co ma być wyświetlane jako nazwa pola (w tym przypadku „Data wydania” zamiast „ReleaseDate”). Atrybut DataType określa typ danych (Data), więc informacje o czasie przechowywane w polu nie są wyświetlane.
Adnotacja danych [Column(TypeName = "decimal(18, 2)")] currency jest wymagana, 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 pomocnik tagów Anchor platformy Core MVC w pliku Views/Movies/Index.cshtml.
<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>
Tag Helpers umożliwiają kodowi po stronie serwera uczestniczenie w tworzeniu i renderowaniu elementów HTML w plikach Razor. W powyższym kodzie element AnchorTagHelper dynamicznie generuje wartość atrybutu HTML href z metody akcji kontrolera i identyfikatora trasy. Użyj pozycji Wyświetl źródło w ulubionej przeglądarce lub narzędzi deweloperskich, aby zbadać wygenerowany znacznik. 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 routingu ustawiony w Startup.cs 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 o Tag Helpers, zobacz Powiązane artykuły.
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 wygenerowany przez plik Edit.cshtmlRazor.
// 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 przekazane 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 over-postingiem. W atrybucie [Bind] należy uwzględnić tylko te właściwości, które chcesz zmienić. Aby uzyskać więcej informacji, zobacz Ochrona kontrolera przed nadmiernym publikowaniem.
ViewModels stanowią alternatywne podejście do zapobiegania zjawisku over-posting.
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ń. Możesz zastosować atrybut [HttpGet] do pierwszej metody edycji, ale nie jest to konieczne, ponieważ [HttpGet] jest ustawieniem domyślnym.
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, zwracany jest kod (HTTP 404) NotFound.
// 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 scaffolding 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 wygenerowany przez scaffolding używa kilku metod Tag Helper w celu usprawnienia znaczników HTML.
Label Tag Helper wyświetla nazwę pola („Title”, „ReleaseDate”, „Genre” lub „Price”).
Pomocnik tagów Input renderuje element HTML <input>.
Tag Helper walidacji 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>
Elementy <input> znajdują się w elemencie HTML <form>, którego atrybut action jest ustawiony na wysyłanie pod adres URL /Movies/Edit/id. Dane formularza zostaną wysłane do serwera po kliknięciu przycisku Save. Ostatni wiersz przed elementem zamykającym </form> pokazuje ukryty token XSRF wygenerowany przez pomocnika tagów formularza.
Przetwarzanie żądania POST
W poniższym [HttpPost] listingu 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 zapobiegających fałszerstwom żądań w pomocniku tagów formularza
system wiązania modelu przyjmuje przesłane wartości formularza i tworzy Movie obiekt, który jest przekazywany jako movie parametr. Właściwość ModelState.IsValid weryfikuje, czy dane przesłane w formularzu mogą służyć do modyfikowania (edytowania lub aktualizowania) obiektu Movie. Jeśli dane są prawidłowe, są zapisywane. Zaktualizowane (edytowane) dane filmu są zapisywane w bazie danych przez wywołanie metody SaveChangesAsync kontekstu bazy danych. Po zapisaniu danych kod przekierowuje użytkownika do metody akcji Index klasy MoviesController, która wyświetla kolekcję filmów, w tym wprowadzone właśnie zmiany.
Przed wysłaniem formularza do serwera 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 wysłany. Jeśli język JavaScript jest wyłączony, nie będzie dostępna walidacja po stronie klienta, ale serwer wykryje przesłane wartości, które są nieprawidłowe, a wartości formularza zostaną ponownie wyświetlone z komunikatami o błędach. W dalszej części samouczka bardziej szczegółowo omówimy walidację modelu.
Pomocnik tagów walidacji w szablonie widoku Views/Movies/Edit.cshtml zajmuje się wyświetlaniem odpowiednich komunikatów o błędach.
Wszystkie metody w kontrolerze filmu HttpGet mają podobny schemat. 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, odbywa się to w przeciążonej wersji metody [HttpPost]. Modyfikowanie danych w metodzie oznaczonej przez 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 utrwalonych danych.
Treści powiązane
- Globalizacja i lokalizacja
- Wprowadzenie do pomocników tagów
- Pomocniki tagów autora
- Zapobieganie atakom fałszerzowania żądań między witrynami (XSRF/CSRF) w ASP.NET Core
- Ochrona kontrolera przed nadmiernym przypisywaniem
- Modele widoków
- Pomocnik tagów formularzy
- Pomocnik tagów input
- Label Tag Helper
- Pomocnik tagów Select
- Tag Helper walidacji