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 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 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.
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?}");
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.
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?}");
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.
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?}");
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 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; }
}
}
W następnym samouczku omówiono DataAnnotations. 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 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 Startup.cs:
app.UseEndpoints(endpoints =>
{
endpoints.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).
Aby uzyskać więcej informacji o Tag Helpers, zobacz Powiązane artykuły.
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, 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ł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] .
[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 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.
[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 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