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 in diesem 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 Web-UI erleichtert 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 entwicklung neuer Apps.

In diesem Abschnitt untersuchen Sie die generierten Edit Aktionsmethoden und -ansichten für den Filmcontroller. Aber zuerst nehmen wir eine kurze Ablenkung, um das Veröffentlichungsdatum besser aussehen zu lassen. Öffnen Sie die Datei "Models\Movie.cs ", und fügen Sie die unten gezeigten 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 wie folgt spezifisch machen:

[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 Uhrzeitinformationen nicht angezeigt werden. Das DisplayFormat-Attribut wird für einen Fehler im Chrome-Browser benötigt, 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 verknüpft ist.

EditLink_sm

Der Link "Bearbeiten" wurde von der Html.ActionLink Methode in der 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 in der System.Web.Mvc.WebViewPage-Basisklasse verfügbar gemacht wird. Die ActionLink Methode des Hilfsprogramm erleichtert das dynamische Generieren von HTML-Links, die mit Aktionsmethoden auf Controllern verknüpft sind. Das erste Argument für die ActionLink Methode ist der zu renderde Verknüpfungstext (z. B <a>Edit Me</a>. ). Das zweite Argument ist der Name der auszuführenden 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 In App_Start\RouteConfig.cs festgelegte Standardroute verwendet das URL-Muster{controller}/{action}/{id}. Daher wird ASP.NET in eine Anforderung an die Aktionsmethode des Movies Controllers mit dem Parameter ID gleich 4 übersetzthttp://localhost:1234/Movies/Edit/4.Edit Überprüfen Sie den folgenden Code aus der Datei App_Start\RouteConfig.cs . Die MapRoute-Methode wird verwendet, um HTTP-Anforderungen an den richtigen Controller und die richtige Aktionsmethode weiterzuleiten und den optionalen ID-Parameter zu liefern. Die MapRoute-Methode wird auch von htmlHelpers verwendet, zActionLink. B. zum Generieren von URLs aufgrund des Controllers, der Aktionsmethode und aller 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. Die URL http://localhost:1234/Movies/Edit?ID=3 übergibt beispielsweise auch den Parameter ID 3 an die Edit Aktionsmethode des Movies Controllers.

EditQueryString

Öffnen Sie den Movies Controller. Die beiden Edit Aktionsmethoden sind unten dargestellt.

// 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 HttpGet Attribut auf die erste Bearbeitungsmethode anwenden, dies ist jedoch nicht erforderlich, da es sich um die Standardeinstellung ist. (Wir verweisen auf Aktionsmethoden, die dem HttpGet Attribut implizit als HttpGet Methoden zugewiesen werden.) Das Bind-Attribut ist ein weiterer wichtiger Sicherheitsmechanismus, der Hacker daran hindert, Daten in Ihrem Modell zu überschreiben. Sie sollten nur Eigenschaften in das Bindungsattribut einschließen, das Sie ändern möchten. Sie können über das Überposten und das Bind-Attribut in meiner Überpostungssicherheitsnotiz lesen. Im in diesem Lernprogramm verwendeten einfachen Modell binden wir alle Daten im Modell. Das ValidateAntiForgeryToken-Attribut wird verwendet, um die Fälschung einer Anforderung zu verhindern und wird in der Bearbeitungsansichtsdatei (Views\Movies\Edit.cshtml) kombiniert@Html.AntiForgeryToken()), ein Teil wird unten 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-Fälschungstoken, das in der Edit Methode des Movies Controllers übereinstimmen muss. Weitere Informationen zur websiteübergreifenden Anforderungsfälschung (auch als XSRF oder CSRF bezeichnet) finden Sie in meinem Lernprogramm XSRF/CSRF Prevention in MVC.

Die HttpGet Edit Methode verwendet den Film-ID-Parameter, sucht den Film mithilfe der Entity Framework-Methode Find und gibt den ausgewählten Film an 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, dass die Ansichtsvorlage oben in der Datei eine @model MvcMovie.Models.Movie Anweisung aufweist . Dies gibt an, dass die Ansicht das Modell für die Ansichtsvorlage vom Typ Movieaufweist.

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

Führen Sie die Anwendung aus, und navigieren Sie zur URL "/Movies ". 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 dem Server gepostet, wenn auf die Schaltfläche "Speichern " geklickt wird. In der zweiten Zeile wird das ausgeblendete XSRF-Token angezeigt, das @Html.AntiForgeryToken() vom 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 vom @Html.AntiForgeryToken() Aufruf in der Ansicht generierte XSRF-Token.

Der ASP.NET MVC-Modellordner verwendet die geposteten Formularwerte und erstellt ein Movie Objekt, das als movie Parameter übergeben wird. Die ModelState.IsValid Überprüfung, ob die im Formular übermittelten Daten verwendet werden können, um ein Movie Objekt zu ändern (bearbeiten oder zu aktualisieren). Wenn die Daten gültig sind, werden die Filmdaten in der Movies Sammlung der db(MovieDBContext Instanz) gespeichert. Die neuen Filmdaten werden in der Datenbank gespeichert, indem die SaveChanges Methode von MovieDBContextaufgerufen wird. 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 nicht gültig bestimmt, wird eine Fehlermeldung angezeigt. Wenn JavaScript deaktiviert ist, ist die clientseitige Überprüfung deaktiviert. Der Server erkennt jedoch, dass die geposteten Werte ungültig sind, und die Formularwerte werden mit Fehlermeldungen erneut angezeigt.

Die Validierung wird später im Lernprogramm ausführlicher untersucht.

Die Html.ValidationMessageFor Hilfsprogramme in der Ansichtsvorlage "Edit.cshtml " kümmern sich um die Anzeige geeigneter Fehlermeldungen.

abcNotValid

HttpGet Alle Methoden folgen einem ähnlichen Muster. Sie erhalten ein Filmobjekt (oder eine Liste von Objekten im Fall von Index), und übergeben das Modell an die Ansicht. Die Create Methode übergibt ein leeres Filmobjekt an die Create-Ansicht. 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 Nr. 46 beschrieben– Verwenden Sie keine Löschlinks, da sie Sicherheitslöcher erstellen. Das Ändern von Daten in einer GET-Methode verstößt auch gegen bewährte HTTP-Methoden und das Architektur-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-Überprüfung für nicht englische Gebietsschemas

Wenn Sie einen US-englischen 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-Überprüfung für nicht englische Gebietsschemas zu unterstützen, die ein Komma (",") für ein Dezimalzeichen und nicht us-englische 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 sie zu verwendenGlobalize.parseFloat. Sie können die nicht englische jQuery-Überprüfung 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 abbildung unten.)

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

    Screenshot des Eingabefelds zum Eingeben von Globalize.

    Wählen Sie jQuery.Validation.Globalize", wählen Sie MvcMovie die Option "Installieren" aus, und klicken Sie auf " Installieren". Die Datei "Scripts\jquery.globalize\globalize.js " wird Ihrem Projekt hinzugefügt. Der Ordner *Scripts\jquery.globalize\cultures* enthält viele Kultur-JavaScript-Dateien. Beachten Sie, dass es fünf Minuten dauern kann, 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 "Bundling" und "Minification".

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

Als temporärer Fix können Sie, wenn Sie keine Überprüfung in Ihrem Gebietsschema erhalten können, erzwingen, dass Ihr Computer US-Englisch verwendet, oder Sie können JavaScript in Ihrem Browser deaktivieren. Um zu erzwingen, dass Ihr Computer US-Englisch verwendet, können Sie das Globalisierungselement zur Stammdatei "web.config " für Projekte hinzufügen. Der folgende Code zeigt das Globalisierungselement, bei dem die Kultur auf USA Englisch festgelegt ist.

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

Im nächsten Lernprogramm implementieren wir Suchfunktionen.