Untersuchen der Bearbeitungsaktionsmethoden und -ansichten für den Filmcontroller

von Rick Anderson

Hinweis

Eine aktualisierte Version dieses Lernprogramms ist hier mit der neuesten Version von Visual Studio verfügbar. Das neue Lernprogramm verwendet ASP.NET Core MVC, was viele Verbesserungen über dieses Lernprogramm bietet.

Dieses Tutorial vermittelt Informationen zu ASP.NET Core MVC mit Controllern und Ansichten. Razor Pages ist eine neue Alternative in ASP.NET Core, einem seitenbasierten Programmiermodell, das das Erstellen von Weboberflächen einfacher und produktiver macht. Es empfiehlt sich, dass Sie sich das Tutorial der Razor Pages vor der MVC-Version ansehen. Das Tutorial zu Razor Pages:

  • Ist einfacher zu befolgen.
  • Behandelt mehr Features.
  • Ist der bevorzugte Ansatz für die neue App-Entwicklung.

In diesem Abschnitt untersuchen Sie die generierten Edit Aktionsmethoden und Ansichten für den Filmcontroller. Aber zuerst nehmen wir eine kurze Diversion, um das Veröffentlichungsdatum besser aussehen zu lassen. Öffnen Sie die Datei "Models\Movie.cs ", und fügen Sie die hervorgehobenen Zeilen hinzu:

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }

    public class MovieDBContext : DbContext
    {
        public DbSet<Movie> Movies { get; set; }
    }
}

Sie können auch die Datumskultur so festlegen:

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

Wir behandeln DataAnnotations im nächsten Tutorial. Das Display-Attribut gibt an, was für den Namen eines Felds angezeigt werden soll (in diesem Fall „Release Date“ anstatt „ReleaseDate“). Das DataType-Attribut gibt den Typ der Daten an, in diesem Fall ist es ein Datum, sodass die im Feld gespeicherten Zeitinformationen nicht angezeigt werden. Das DisplayFormat-Attribut ist für einen Fehler im Chrome-Browser erforderlich, der Datumsformate falsch rendert.

Führen Sie die Anwendung aus, und navigieren Sie zum Movies Controller. Halten Sie den Mauszeiger über einen Bearbeitungslink , um die URL anzuzeigen, mit der sie links.

EditLink_sm

Der Link "Bearbeiten " wurde durch die Methode in der Html.ActionLink Ansicht "Views\Movies\Index.cshtml " generiert:

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

Html.ActionLink

Das Html Objekt ist ein Hilfsprogramm, das mithilfe einer Eigenschaft auf der System.Web.Mvc.WebViewPage-Basisklasse verfügbar gemacht wird. Die ActionLink Methode des Hilfsers erleichtert es, HTML-Hyperlinks dynamisch zu generieren, die mit Aktionsmethoden auf Controllern verknüpft sind. Das erste Argument für die ActionLink Methode ist der Linktext zum Rendern (z <a>Edit Me</a>. B. ). Das zweite Argument ist der Name der zu aufrufenden Aktionsmethode (In diesem Fall die Edit Aktion). Das letzte Argument ist ein anonymes Objekt , das die Routendaten generiert (in diesem Fall die ID von 4).

Der generierte Link, der in der vorherigen Abbildung angezeigt wird, ist http://localhost:1234/Movies/Edit/4. Die Standardroute (in App_Start\RouteConfig.cs) verwendet das URL-Muster {controller}/{action}/{id}. Daher wird ASP.NET in eine Anforderung an die Edit Aktionsmethode des Movies Controllers http://localhost:1234/Movies/Edit/4 mit dem Parameter ID gleich 4 übersetzt. Überprüfen Sie den folgenden Code aus der Datei "App_Start\RouteConfig.cs ". Die MapRoute-Methode wird zum Weiterleiten von HTTP-Anforderungen an die richtige Controller- und Aktionsmethode verwendet und geben den optionalen ID-Parameter an. Die MapRoute-Methode wird auch von den HtmlHelpers verwendet, z ActionLink . B. zum Generieren von URLs mit dem Controller, der Aktionsmethode und allen Routendaten.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", 
            id = UrlParameter.Optional }
    );
}

Sie können auch Aktionsmethodenparameter mithilfe einer Abfragezeichenfolge übergeben. Beispielsweise übergibt die URL http://localhost:1234/Movies/Edit?ID=3 auch den Parameter ID 3 an die Edit Aktionsmethode des Movies Controllers.

EditQueryString

Öffnen Sie den Movies Controller. Die beiden Edit Aktionsmethoden werden unten angezeigt.

// GET: /Movies/Edit/5
public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    return View(movie);
}

// POST: /Movies/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Beachten Sie, dass der zweiten Edit-Aktionsmethode das HttpPost-Attribut vorangestellt ist. Dieses Attribut gibt an, dass die Überladung der Edit Methode nur für POST-Anforderungen aufgerufen werden kann. Sie können das Attribut auf die HttpGet erste Bearbeitungsmethode anwenden, das ist jedoch nicht erforderlich, da es sich um die Standardeinstellung handeln soll. (Wir verweisen auf Aktionsmethoden, die implizit dem HttpGet Attribut als HttpGet Methoden zugewiesen werden.) Das Bind-Attribut ist ein weiterer wichtiger Sicherheitsmechanismus, der Hacker von überschreibenden Daten an Ihr Modell hält. Sie sollten nur Eigenschaften in das Bindungsattribute einschließen, das Sie ändern möchten. Sie können über die Überpostung und das Bindungsattribute in meiner Überpostungssicherheitsnotiz lesen. Im einfachen Modell, das in diesem Lernprogramm verwendet wird, binden wir alle Daten im Modell. Das ValidateAntiForgeryToken-Attribut wird verwendet, um Fälschungen einer Anforderung zu verhindern und @Html.AntiForgeryToken() in der Bearbeitungsansichtsdatei (Views\Movies\Edit.cshtml) zu verhindern, wird unten ein Teil angezeigt:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.ID)

        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>

@Html.AntiForgeryToken() generiert ein ausgeblendetes Formular-Anti-Forgery-Token, das in der Edit Methode des Movies Controllers übereinstimmen muss. Sie können mehr über die Websiteanforderungssuche (auch als XSRF oder CSRF bezeichnet) in meinem Lernprogramm XSRF/CSRF Prevention in MVC lesen.

Die HttpGetEdit Methode verwendet den Film-ID-Parameter, sucht den Film mithilfe der Entity Framework-Methode Find nach, und gibt den ausgewählten Film in die Bearbeitungsansicht zurück. Wenn ein Film nicht gefunden werden kann, wird HttpNotFound zurückgegeben. Als das Gerüstsystem die Bearbeitungsansicht erstellt hat, wurde die Movie-Klasse überprüft und Code zum Rendern der <label>- und <input>-Elemente für jede Eigenschaft der Klasse erstellt. Das folgende Beispiel zeigt die Bearbeitungsansicht, die vom Visual Studio-Gerüstsystem generiert wurde:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.ID)

        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ReleaseDate)
                @Html.ValidationMessageFor(model => model.ReleaseDate)
            </div>
        </div>
        @*Genre and Price removed for brevity.*@        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Beachten Sie, wie die Ansichtsvorlage am oberen Rand der Datei eine @model MvcMovie.Models.Movie Anweisung hat – dies gibt an, dass die Ansicht das Modell für die Ansichtsvorlage vom Typ Movieerwartet.

Der Gerüstcode verwendet mehrere Hilfsmethoden , um das HTML-Markup zu optimieren. Der Html.LabelFor Hilfsprogramm zeigt den Namen des Felds ("Titel", "ReleaseDate", "Genre" oder "Preis"). Der Html.EditorFor Hilfsprogramm rendert ein HTML-Element <input> . Der Html.ValidationMessageFor Hilfsprogramm zeigt alle Überprüfungsnachrichten an, die dieser Eigenschaft zugeordnet sind.

Führen Sie die Anwendung aus, und navigieren Sie zur /Movies-URL . Klicken Sie auf einen Link Bearbeiten. Zeigen Sie im Browser den Quelltext für die Seite an. Der HTML-Code für das Formularelement wird unten angezeigt.

<form action="/movies/Edit/4" method="post">
   <input name="__RequestVerificationToken" type="hidden" value="UxY6bkQyJCXO3Kn5AXg-6TXxOj6yVBi9tghHaQ5Lq_qwKvcojNXEEfcbn-FGh_0vuw4tS_BRk7QQQHlJp8AP4_X4orVNoQnp2cd8kXhykS01" />  <fieldset class="form-horizontal">
      <legend>Movie</legend>

      <input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

      <div class="control-group">
         <label class="control-label" for="Title">Title</label>
         <div class="controls">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="GhostBusters" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Title" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="ReleaseDate">Release Date</label>
         <div class="controls">
            <input class="text-box single-line" data-val="true" data-val-date="The field Release Date must be a date." data-val-required="The Release Date field is required." id="ReleaseDate" name="ReleaseDate" type="date" value="1/1/1984" />
            <span class="field-validation-valid help-inline" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="Genre">Genre</label>
         <div class="controls">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Comedy" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="control-group">
         <label class="control-label" for="Price">Price</label>
         <div class="controls">
            <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="7.99" />
            <span class="field-validation-valid help-inline" data-valmsg-for="Price" data-valmsg-replace="true"></span>
         </div>
      </div>

      <div class="form-actions no-color">
         <input type="submit" value="Save" class="btn" />
      </div>
   </fieldset>
</form>

Die <input> Elemente befinden sich in einem HTML-Element <form> , dessen action Attribut auf die URL "/Movies/Edit " festgelegt ist. Die Formulardaten werden auf den Server gesendet, wenn auf die Schaltfläche "Speichern " geklickt wird. Die zweite Zeile zeigt das ausgeblendete XSRF-Token , das vom @Html.AntiForgeryToken() Aufruf generiert wird.

Verarbeiten der POST-Anforderung

Die folgende Liste zeigt die HttpPost-Version der Edit-Aktionsmethode.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Das ValidateAntiForgeryToken-Attribut überprüft das XSRF-Token , das vom Aufruf in der @Html.AntiForgeryToken() Ansicht generiert wird.

Der ASP.NET MVC-Modellbinder nimmt die geposteten Formularwerte und erstellt ein Movie Objekt, das als movie Parameter übergeben wird. Die ModelState.IsValid Überprüfung, dass die im Formular übermittelten Daten verwendet werden können, um ein Movie Objekt zu ändern (bearbeiten oder aktualisieren). Wenn die Daten gültig sind, werden die Filmdaten in der Movies Auflistung der db(MovieDBContext Instanz) gespeichert. Die neuen Filmdaten werden in der Datenbank gespeichert, indem sie die SaveChanges Methode aufrufen MovieDBContext. Nach dem Speichern der Daten leitet der Code den Benutzer an die Index-Aktionsmethode der MoviesController-Klasse weiter, die die Filmsammlung einschließlich der gerade vorgenommenen Änderungen anzeigt.

Sobald die clientseitige Überprüfung den Wert eines Felds bestimmt, wird eine Fehlermeldung angezeigt. Wenn JavaScript deaktiviert ist, ist die clientseitige Überprüfung deaktiviert. Der Server erkennt jedoch die geposteten Werte nicht, und die Formularwerte werden mit Fehlermeldungen erneut angezeigt.

Die Überprüfung wird später im Lernprogramm ausführlicher untersucht.

Die Html.ValidationMessageFor Hilfser in der Vorlagenvorlage "Edit.cshtml " sorgen dafür, dass entsprechende Fehlermeldungen angezeigt werden.

abcNotValid

Alle Methoden folgen einem ähnlichen HttpGet Muster. Sie erhalten ein Filmobjekt (oder eine Liste von Objekten im IndexFalle von ) und übergeben das Modell an die Ansicht. Die Create Methode übergibt ein leeres Filmobjekt an die Ansicht "Erstellen". Alle Methoden, die Daten erstellen, bearbeiten, löschen oder in beliebiger Weise ändern, nutzen dazu die HttpPost-Überladung der Methode. Das Ändern von Daten in einer HTTP GET-Methode ist ein Sicherheitsrisiko, wie im Blogbeitragseintrag ASP.NET MVC-Tipp #46 beschrieben – Verwenden Sie keine Delete Links, weil sie Sicherheitslöcher erstellen. Das Ändern von Daten in einer GET-Methode verstößt auch gegen HTTP-bewährte Methoden und das architektonische REST-Muster , das angibt, dass GET-Anforderungen den Zustand Ihrer Anwendung nicht ändern sollten. Die Durchführung eines GET-Vorgangs sollte also eine sichere Operation sein, die keine Nebenwirkungen hat und die permanenten Daten nicht ändert.

jQuery-Validierung für nicht englische Gebietsschemas

Wenn Sie einen US-English Computer verwenden, können Sie diesen Abschnitt überspringen und zum nächsten Lernprogramm wechseln. Sie können die Globalize-Version dieses Lernprogramms hier herunterladen. Ein hervorragendes Lernprogramm zur Internationalisierung finden Sie unter Nadeems ASP.NET MVC 5 Internationalization.

Hinweis

um die jQuery-Validierung für nicht englische Gebietsschemas zu unterstützen, die ein Komma (",") für einen Dezimalpunkt und nicht US-English Datumsformate verwenden, müssen Sie globalize.js und Ihre spezifischen Kulturen/globalize.cultures.js Datei(aus https://github.com/jquery/globalize ) und JavaScript verwenden, um zu verwenden Globalize.parseFloat. Sie können die jQuery-Nicht-Englisch-Validierung von NuGet abrufen. (Installieren Sie "Globalize" nicht, wenn Sie ein englisches Gebietsschema verwenden.)

  1. Klicken Sie im Menü "Extras " auf "NuGet-Paket-Manager", und klicken Sie dann auf "NuGet-Pakete für Lösung verwalten".

    Screenshot des Menüs

  2. Wählen Sie im linken Bereich "Durchsuchen*" aus. *(Siehe unten.)

  3. Geben Sie im Eingabefeld "Globalize*" ein.

    Screenshot des Eingabefelds, um Globalize einzugeben.

    Wählen Sie , wählen MvcMovie Sie und klicken Sie jQuery.Validation.Globalizeauf "Installieren". Die Scripts\jquery.globalize\globalize.js Datei wird Ihrem Projekt hinzugefügt. Der Ordner *Scripts\jquery.globalize\culture* enthält viele Kultur-JavaScript-Dateien. Beachten Sie, dass es fünf Minuten dauern kann, um dieses Paket zu installieren.

    Der folgende Code zeigt die Änderungen an der Datei "Views\Movies\Edit.cshtml":

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

<script src="~/Scripts/globalize/globalize.js"></script>
<script src="~/Scripts/globalize/cultures/globalize.culture.@(System.Threading.Thread.CurrentThread.CurrentCulture.Name).js"></script>
<script>
    $.validator.methods.number = function (value, element) {
        return this.optional(element) ||
            !isNaN(Globalize.parseFloat(value));
    }
    $(document).ready(function () {
        Globalize.culture('@(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
    });
</script>
<script>
    jQuery.extend(jQuery.validator.methods, {
        range: function (value, element, param) {
            //Use the Globalization plugin to parse the value
            var val = Globalize.parseFloat(value);
            return this.optional(element) || (
                val >= param[0] && val <= param[1]);
        }
    });
    $.validator.methods.date = function (value, element) {
        return this.optional(element) ||
            Globalize.parseDate(value) ||
            Globalize.parseDate(value, "yyyy-MM-dd");
    }
</script>
}

Um diesen Code in jeder Bearbeitungsansicht zu vermeiden, können Sie ihn in die Layoutdatei verschieben. Informationen zum Optimieren des Skriptdownloads finden Sie in meinem Lernprogramm "Bündelung" und "Minification".

Weitere Informationen finden Sie unter ASP.NET MVC 3 Internationalization und ASP.NET MVC 3 Internationalization - Teil 2 (NerdDinner).

Wenn Sie die Überprüfung nicht in Ihrem Gebietsschema erhalten können, können Sie Ihren Computer zum Verwenden von US-Englisch erzwingen oder JavaScript in Ihrem Browser deaktivieren. Um Ihren Computer zum Verwenden von US-Englisch zu erzwingen, können Sie dem Projektstamm web.configDatei das Globalisierungselement hinzufügen. Der folgende Code zeigt das Globalisierungselement mit der Kultur, die auf USA Englisch festgelegt ist.

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

Im nächsten Lernprogramm implementieren wir Suchfunktionen.