Freigeben über


Implementieren einer Auflistungs-/Detailbenutzeroberfläche mit Controllern und Ansichten

von Microsoft

PDF herunterladen

Dies ist Schritt 4 eines kostenlosen "NerdDinner"-Anwendungstutorial , das die Erstellung einer kleinen, aber vollständigen Webanwendung mit ASP.NET MVC 1 exemplarische Schritte durchläuft.

Schritt 4 zeigt, wie Sie der Anwendung einen Controller hinzufügen, der unser Modell nutzt, um Benutzern eine Navigationsoberfläche für Datenauflistungen/Details für Abendessen auf unserer NerdDinner-Website bereitzustellen.

Wenn Sie ASP.NET MVC 3 verwenden, empfiehlt es sich, die Tutorials Erste Schritte Mit MVC 3 oder MVC Music Store zu befolgen.

NerdDinner Schritt 4: Controller und Ansichten

Bei herkömmlichen Webframeworks (klassische ASP, PHP, ASP.NET Web Forms usw.) werden eingehende URLs in der Regel Dateien auf dem Datenträger zugeordnet. Beispiel: Eine Anforderung für eine URL wie "/Products.aspx" oder "/Products.php" kann von einer Datei "Products.aspx" oder "Products.php" verarbeitet werden.

Webbasierte MVC-Frameworks ordnen URLs auf etwas andere Weise Servercode zu. Anstatt eingehende URLs Dateien zuzuordnen, ordnen sie stattdessen URLs Methoden in Klassen zu. Diese Klassen werden als "Controller" bezeichnet und sind für die Verarbeitung eingehender HTTP-Anforderungen, die Verarbeitung von Benutzereingaben, das Abrufen und Speichern von Daten und die Bestimmung der Antwort zum Senden an den Client (Anzeigen von HTML, Herunterladen einer Datei, Umleitung zu einer anderen URL usw.) verantwortlich.

Nachdem wir nun ein grundlegendes Modell für unsere NerdDinner-Anwendung erstellt haben, besteht unser nächster Schritt darin, der Anwendung einen Controller hinzuzufügen, der ihn nutzt, um Benutzern eine Datenauflistung/Detailnavigation für Dinners auf unserer Website zu bieten.

Hinzufügen eines DinnersController-Controllers

Klicken Sie zunächst mit der rechten Maustaste auf den Ordner "Controller" in unserem Webprojekt, und wählen Sie dann den Menübefehl Add-Controller> aus (Sie können diesen Befehl auch ausführen, indem Sie STRG-M, STRG-C eingeben):

Screenshot des fensters Projektmappen-Explorer mit dem Ordner Controller und den blau hervorgehobenen Menüelementen

Dadurch wird das Dialogfeld "Controller hinzufügen" geöffnet:

Screenshot des Dialogfelds Controller hinzufügen mit dem Feld Controllername mit dem Text Dinners Controller

Wir nennen den neuen Controller "DinnersController" und klicken auf die Schaltfläche "Hinzufügen". Visual Studio fügt dann eine DinnersController.cs-Datei unter dem Verzeichnis \Controllers hinzu:

Screenshot des Projektmappen-Explorer Fensters mit der blau hervorgehobenen Datei

Außerdem wird die neue DinnersController-Klasse im Code-Editor geöffnet.

Hinzufügen von Index()- und Details()-Aktionsmethoden zur DinnersController-Klasse

Wir möchten es Besuchern mit unserer Anwendung ermöglichen, eine Liste mit bevorstehenden Abendessen zu durchsuchen, und ihnen das Klicken auf ein beliebiges Abendessen in der Liste ermöglichen, um bestimmte Details darüber anzuzeigen. Dazu veröffentlichen wir die folgenden URLs aus unserer Anwendung:

URL Zweck
/Abendessen/ Anzeigen einer HTML-Liste anstehender Abendessen
/Dinners/Details/[id] Zeigen Sie Details zu einem bestimmten Abendessen an, das durch einen in der URL eingebetteten Parameter "id" angezeigt wird, der mit der DinnerID des Abendessens in der Datenbank übereinstimmt. Beispiel: /Dinners/Details/2 zeigt eine HTML-Seite mit Details zum Dinner an, dessen DinnerID-Wert 2 ist.

Wir werden erste Implementierungen dieser URLs veröffentlichen, indem wir unserer DinnersController-Klasse wie folgt zwei öffentliche "Aktionsmethoden" hinzufügen:

public class DinnersController : Controller {

    //
    // HTTP-GET: /Dinners/

    public void Index() {
        Response.Write("<h1>Coming Soon: Dinners</h1>");
    }

    //
    // HTTP-GET: /Dinners/Details/2

    public void Details(int id) {
        Response.Write("<h1>Details DinnerID: " + id + "</h1>");
    }
}

Anschließend führen wir die NerdDinner-Anwendung aus und verwenden unseren Browser, um sie aufzurufen. Wenn Sie die URL "/Dinners/" eingeben, wird die Index()- Methode ausgeführt, und sie sendet die folgende Antwort zurück:

Screenshot des Antwortfensters, das beim Ausführen der NerdDinner-Anwendung generiert wurde und den Text Coming Soon: Dinners zeigt.

Wenn Sie die URL "/Dinners/Details/2" eingeben, wird unsere Details() -Methode ausgeführt und die folgende Antwort zurück gesendet:

Screenshot des Antwortfensters, das beim Ausführen der NerdDinner-Anwendung generiert wurde und den Text Details Dinner I D: 2 zeigt.

Vielleicht fragen Sie sich, wie ASP.NET MVC wusste, unsere DinnersController-Klasse zu erstellen und diese Methoden aufzurufen? Um dies zu verstehen, werfen wir einen kurzen Blick auf die Funktionsweise des Routings.

Grundlegendes zu ASP.NET MVC-Routing

ASP.NET MVC enthält eine leistungsstarke URL-Routing-Engine, die viel Flexibilität bei der Steuerung der Zuordnung von URLs zu Controllerklassen bietet. Es ermöglicht uns, vollständig anzupassen, wie ASP.NET MVC die zu erstellende Controllerklasse auswählt, welche Methode darauf aufgerufen werden soll, sowie verschiedene Möglichkeiten zu konfigurieren, wie Variablen automatisch aus der URL/Querystring analysiert und als Parameterargumente an die -Methode übergeben werden können. Es bietet die Flexibilität, eine Website für SEO (Suchmaschinenoptimierung) vollständig zu optimieren und jede URL-Struktur zu veröffentlichen, die wir von einer Anwendung benötigen.

Standardmäßig verfügen neue ASP.NET MVC-Projekte über einen vorkonfigurierten Satz bereits registrierter URL-Routingregeln. Dies ermöglicht es uns, einfach mit einer Anwendung zu beginnen, ohne etwas explizit konfigurieren zu müssen. Die Standardroutingregelregistrierungen finden Sie in der Klasse "Application" unserer Projekte, die wir öffnen können, indem Sie im Stamm unseres Projekts auf die Datei "Global.asax" doppelklicken:

Screenshot des fensters Projektmappen-Explorer mit dem globalen Punkt a s a x datei in blau hervorgehoben und rot eingekreist.

Die Standardmäßigen ASP.NET MVC-Routingregeln werden in der "RegisterRoutes"-Methode dieser Klasse registriert:

public void RegisterRoutes(RouteCollection routes) {

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                       // Route name
        "{controller}/{action}/{id}",                    // URL w/ params
        new { controller="Home", action="Index",id="" }  // Param defaults
    );
}

Die "Routen. Der obige MapRoute()"-Methodenaufruf registriert eine Standardroutingregel, die eingehende URLs Controllerklassen ordnet, die das URL-Format verwenden: "/{controller}/{action}/{id}" – wobei "controller" der Name der instanziierten Controllerklasse ist, "action" der Name einer öffentlichen Methode, die darauf aufgerufen werden soll, und "id" ist ein optionaler Parameter, der in der URL eingebettet ist, der als Argument an die -Methode übergeben werden kann. Der dritte Parameter, der an den Aufruf der "MapRoute()"-Methode übergeben wird, ist ein Satz von Standardwerten, die für die Werte controller/action/id verwendet werden sollen, falls sie in der URL nicht vorhanden sind (Controller = "Home", Action="Index", Id=").

Im Folgenden finden Sie eine Tabelle, in der veranschaulicht wird, wie eine Vielzahl von URLs mithilfe der Standardrouteregel "/{controller}/{action}/{id}" zugeordnet werden:

URL Controllerklasse Aktionsmethode Übergebene Parameter
/Abendessen/Details/2 DinnersController Details(id) id=2
/Dinners/Edit/5 DinnersController Edit(id) id=5
/Dinners/Create DinnersController Create()
/Abendessen DinnersController Index()
/Startseite Homecontroller Index()
/ Homecontroller Index()

Die letzten drei Zeilen zeigen die verwendeten Standardwerte (Controller = Home, Action = Index, Id = "") an. Da die "Index"-Methode als Standardaktionsname registriert wird, wenn keiner angegeben wird, führen die URLs "/Dinners" und "/Home" dazu, dass die Index()-Aktionsmethode für ihre Controller-Klassen aufgerufen wird. Da der "Home"-Controller als Standardcontroller registriert wird, wenn er nicht angegeben wird, bewirkt die URL "/", dass der HomeController erstellt und die Index()-Aktionsmethode darauf aufgerufen wird.

Wenn Sie diese Standard-URL-Routingregeln nicht mögen, ist die gute Nachricht, dass sie einfach geändert werden können . Bearbeiten Sie sie einfach in der oben genannten RegisterRoutes-Methode. Für unsere NerdDinner-Anwendung ändern wir jedoch keine der Standard-URL-Routingregeln . Stattdessen verwenden wir sie nur unverändert.

Verwenden des DinnerRepository aus unserem DinnersController

Ersetzen wir nun unsere aktuelle Implementierung der Aktionsmethoden Index() und Details() von DinnersController durch Implementierungen, die unser Modell verwenden.

Wir verwenden die zuvor erstellte DinnerRepository-Klasse, um das Verhalten zu implementieren. Zunächst fügen wir eine using-Anweisung hinzu, die auf den Namespace "NerdDinner.Models" verweist, und deklarieren dann einen instance unseres DinnerRepository als Feld in unserer DinnerController-Klasse.

Weiter unten in diesem Kapitel werden wir das Konzept der "Abhängigkeitsinjektion" vorstellen und eine andere Möglichkeit für unsere Controller zeigen, einen Verweis auf ein DinnerRepository zu erhalten, der bessere Komponententests ermöglicht. Im Moment erstellen wir jedoch nur eine instance unserer DinnerRepository-Inline wie unten.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NerdDinner.Models;

namespace NerdDinner.Controllers {

    public class DinnersController : Controller {

        DinnerRepository dinnerRepository = new DinnerRepository();

        //
        // GET: /Dinners/

        public void Index() {
            var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        }

        //
        // GET: /Dinners/Details/2

        public void Details(int id) {
            Dinner dinner = dinnerRepository.GetDinner(id);
        }
    }
}

Jetzt sind wir bereit, mithilfe unserer abgerufenen Datenmodellobjekte eine HTML-Antwort zurück zu generieren.

Verwenden von Ansichten mit unserem Controller

Es ist zwar möglich, Code innerhalb unserer Aktionsmethoden zu schreiben, um HTML zu assemblieren und dann die Response.Write() -Hilfsmethode zu verwenden, um ihn zurück an den Client zu senden, aber dieser Ansatz wird schnell ziemlich unhandlich. Ein viel besserer Ansatz besteht darin, dass wir nur Anwendungs- und Datenlogik innerhalb unserer DinnersController-Aktionsmethoden ausführen und dann die Zum Rendern einer HTML-Antwort erforderlichen Daten an eine separate "Ansicht"-Vorlage übergeben, die für die Ausgabe der HTML-Darstellung verantwortlich ist. Wie wir gleich sehen werden, ist eine "Ansicht"-Vorlage eine Textdatei, die in der Regel eine Kombination aus HTML-Markup und eingebettetem Renderingcode enthält.

Die Trennung unserer Controllerlogik von unserem Ansichtsrendering bringt mehrere große Vorteile. Insbesondere trägt es dazu bei, eine klare "Trennung der Bedenken" zwischen dem Anwendungscode und dem Formatierungs-/Renderingcode der Benutzeroberfläche zu erzwingen. Dies erleichtert das Testen von Komponentenlogik in der Anwendungslogik isoliert von der Renderinglogik der Benutzeroberfläche. Dies erleichtert das spätere Ändern der Benutzeroberflächenrenderingvorlagen, ohne änderungen am Anwendungscode vornehmen zu müssen. Und es kann Entwicklern und Designern die Zusammenarbeit an Projekten erleichtern.

Wir können unsere DinnersController-Klasse aktualisieren, um anzugeben, dass wir eine Ansichtsvorlage verwenden möchten, um eine HTML-UI-Antwort zurückzusenden, indem wir die Methodensignaturen unserer beiden Aktionsmethoden vom Rückgabetyp "void" in den Rückgabetyp "ActionResult" ändern. Anschließend können wir die View() -Hilfsmethode für die Controller-Basisklasse aufrufen, um ein "ViewResult"-Objekt wie folgt zurückzugeben:

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View("Index", dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }
}

Die Signatur der View() -Hilfsmethode, die wir oben verwenden, sieht wie folgt aus:

Screenshot der View-Hilfsmethode mit dem Text Ergebnisansicht anzeigen (Name der Zeichenfolgenansicht, Objektmodell).

Der erste Parameter für die View() -Hilfsmethode ist der Name der Ansichtsvorlagendatei, die zum Rendern der HTML-Antwort verwendet werden soll. Der zweite Parameter ist ein Modellobjekt, das die Daten enthält, die die Ansichtsvorlage zum Rendern der HTML-Antwort benötigt.

Innerhalb unserer Index()-Aktionsmethode rufen wir die View() -Hilfsmethode auf und geben an, dass wir eine HTML-Auflistung von Dinners mithilfe einer "Index"-Ansichtsvorlage rendern möchten. Wir übergeben der Ansichtsvorlage eine Sequenz von Dinner-Objekten, aus denen die Liste generiert werden soll:

//
    // GET: /Dinners/

    public ActionResult Index() {
    
        var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        
        return View("Index", dinners);
    }

Innerhalb unserer Aktionsmethode Details() versuchen wir, ein Dinner-Objekt mithilfe der in der URL angegebenen ID abzurufen. Wenn ein gültiges Dinner gefunden wird, rufen wir die View() -Hilfsmethode auf, die angibt, dass wir eine Ansichtsvorlage "Details" verwenden möchten, um das abgerufene Dinner-Objekt zu rendern. Wenn ein ungültiges Abendessen angefordert wird, wird eine hilfreiche Fehlermeldung gerendert, die angibt, dass das Dinner nicht vorhanden ist, indem eine "NotFound"-Ansichtsvorlage verwendet wird (und eine überladene Version der View() -Hilfsmethode, die nur den Vorlagennamen annimmt:

//
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.FindDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }

Implementieren wir nun die Ansichtsvorlagen "NotFound", "Details" und "Index".

Implementieren der Ansichtsvorlage "NotFound"

Wir beginnen mit der Implementierung der Ansichtsvorlage "NotFound", die eine benutzerfreundliche Fehlermeldung anzeigt, dass das angeforderte Abendessen nicht gefunden werden kann.

Wir erstellen eine neue Ansichtsvorlage, indem wir den Textcursor in einer Controlleraktionsmethode positionieren und dann mit der rechten Maustaste klicken und den Menübefehl "Ansicht hinzufügen" auswählen (wir können diesen Befehl auch ausführen, indem wir STRG-M, STRG-V eingeben):

Screenshot des Projekts mit dem Mit der rechten Maustaste geklickten Menüelement Ansicht hinzufügen in blau hervorgehoben und rot eingekreist.

Dadurch wird ein Dialogfeld "Ansicht hinzufügen" wie unten angezeigt. Standardmäßig füllt das Dialogfeld den Namen der zu erstellenden Ansicht vorab auf, um dem Namen der Aktionsmethode zu entsprechen, in der sich der Cursor befand, als das Dialogfeld gestartet wurde (in diesem Fall "Details"). Da wir zuerst die Vorlage "NotFound" implementieren möchten, überschreiben wir diesen Ansichtsnamen und legen sie stattdessen auf "NotFound" fest:

Screenshot des Fensters Ansicht hinzufügen, in dem das Feld Ansichtsname auf Nicht gefunden festgelegt ist, das Kontrollkästchen Master Seite auswählen aktiviert ist und der Inhaltsplatzhalter I D auf Hauptinhalt festgelegt ist.

Wenn wir auf die Schaltfläche "Hinzufügen" klicken, erstellt Visual Studio eine neue Ansichtsvorlage "NotFound.aspx" für uns im Verzeichnis "\Views\Dinners" (die auch erstellt wird, wenn das Verzeichnis noch nicht vorhanden ist):

Screenshot der Ordnerhierarchie des Projektmappen-Explorer Fensters mit blau hervorgehobenem Punkt

Außerdem wird unsere neue Ansichtsvorlage "NotFound.aspx" im Code-Editor geöffnet:

Screenshot des Code-Editor-Fensters mit dem Nicht gefundenen Punkt a s p x-Datei, das im Code-Editor geöffnet wurde.

Anzeigen von Vorlagen verfügen standardmäßig über zwei "Inhaltsregionen", in denen Inhalte und Code hinzugefügt werden können. Die erste ermöglicht es uns, den "Titel" der zurückgesendeten HTML-Seite anzupassen. Die zweite ermöglicht es uns, den "Standard Inhalt" der zurückgesendeten HTML-Seite anzupassen.

Um unsere Ansichtsvorlage "NotFound" zu implementieren, fügen wir einige grundlegende Inhalte hinzu:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner Not Found
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Dinner Not Found</h2>

    <p>Sorry - but the dinner you requested doesn't exist or was deleted.</p>

</asp:Content>

Wir können es dann im Browser ausprobieren. Dazu fordern wir die URL "/Dinners/Details/9999" an. Dies bezieht sich auf ein Abendessen, das derzeit nicht in der Datenbank vorhanden ist, und bewirkt, dass unsere DinnersController.Details()-Aktionsmethode unsere "NotFound"-Ansichtsvorlage rendert:

Screenshot: Fenster

Eine Sache, die Sie im obigen Screenshot bemerken werden, ist, dass unsere grundlegende Ansichtsvorlage eine Reihe von HTML-Code geerbt hat, der den Standard Inhalt auf dem Bildschirm umgibt. Dies liegt daran, dass unsere Ansichtsvorlage eine Vorlage "master Seite" verwendet, die es uns ermöglicht, ein konsistentes Layout auf alle Ansichten auf der Website anzuwenden. In einem späteren Teil dieses Tutorials wird erläutert, wie master Seiten mehr funktionieren.

Implementieren der Ansichtsvorlage "Details"

Implementieren wir nun die Ansichtsvorlage "Details", die HTML für ein einzelnes Dinner-Modell generiert.

Dazu positionieren Sie den Textcursor in der Aktionsmethode Details, klicken Sie dann mit der rechten Maustaste, und wählen Sie den Menübefehl "Ansicht hinzufügen" aus (oder drücken Sie STRG-M, STRG-V):

Screenshot des Code-Editor-Fensters mit dem Rechtsklickmenüelement Add View dot dot in rot hervorgehoben.

Dadurch wird das Dialogfeld "Ansicht hinzufügen" geöffnet. Wir behalten den Standardansichtsnamen ("Details") bei. Außerdem aktivieren wir im Dialogfeld das Kontrollkästchen "Stark typisierte Ansicht erstellen" und wählen (mithilfe der Dropdownliste des Kombinationsfelds) den Namen des Modelltyps aus, den wir vom Controller an die Ansicht übergeben. Für diese Ansicht übergeben wir ein Dinner-Objekt (der vollqualifizierte Name für diesen Typ lautet: "NerdDinner.Models.Dinner"):

Screenshot des Fensters Ansicht hinzufügen, in dem die Dropdownliste Inhalt anzeigen auf Details festgelegt ist und die Datenklasse Ansicht auf Nerd Dinner dot Models dot Dinner festgelegt ist.

Im Gegensatz zur vorherigen Vorlage, bei der wir uns für die Erstellung einer "leeren Ansicht" entschieden haben, wird die Ansicht dieses Mal automatisch mithilfe einer Vorlage "Details" gerüstet. Wir können dies angeben, indem Sie die Dropdownliste "Inhalt anzeigen" im obigen Dialogfeld ändern.

"Gerüstbau" generiert eine erste Implementierung unserer Detailansichtsvorlage basierend auf dem Dinner-Objekt, das wir an sie übergeben. Dies bietet uns eine einfache Möglichkeit, schnell mit der Implementierung von Ansichtsvorlagen zu beginnen.

Wenn wir auf die Schaltfläche "Hinzufügen" klicken, erstellt Visual Studio eine neue Ansichtsvorlagendatei "Details.aspx" für uns in unserem Verzeichnis "\Views\Dinners":

Screenshot des fensters Projektmappen-Explorer mit der Ordnerhierarchie mit blau hervorgehobenem Ordner Dinners

Außerdem wird die neue Ansichtsvorlage "Details.aspx" im Code-Editor geöffnet. Es enthält eine anfängliche Gerüstimplementierung einer Detailansicht, die auf einem Dinner-Modell basiert. Die Gerüstbau-Engine verwendet .NET-Reflektion, um die öffentlichen Eigenschaften zu betrachten, die für die übergebene Klasse verfügbar gemacht werden, und fügt basierend auf jedem gefundenen Typ geeignete Inhalte hinzu:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Details
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Details</h2>

    <fieldset>
        <legend>Fields</legend>
        <p>
            DinnerID:
            <%=Html.Encode(Model.DinnerID) %>
        </p>
        <p>
            Title:
            <%=Html.Encode(Model.Title) %>
        </p>
        <p>
            EventDate:
            <%= Html.Encode(String.Format("{0:g}", Model.EventDate)) %>
        </p>
        <p>
            Description:
            <%=Html.Encode(Model.Description) %>
        </p>
        <p>
            HostedBy:
            <%=Html.Encode(Model.HostedBy) %>
        </p>
        <p>
            ContactPhone:
            <%=Html.Encode(Model.ContactPhone) %>
        </p>
        <p>
            Address:
            <%=Html.Encode(Model.Address) %>
        </p>
        <p>
            Country:
            <%=Html.Encode(Model.Country) %>
        </p>
        <p>
            Latitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Latitude)) %>
        </p>
        <p>
            Longitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Longitude)) %>
        </p>
    </fieldset>
    
    <p>
        <%=Html.ActionLink("Edit","Edit", new { id=Model.DinnerID }) %>|
        <%=Html.ActionLink("Back to List", "Index") %>
    </p>
    
</asp:Content>

Wir können die URL "/Dinners/Details/1" anfordern, um zu sehen, wie diese "Details"-Gerüstimplementierung im Browser aussieht. Wenn Sie diese URL verwenden, wird eines der Abendessen angezeigt, die wir unserer Datenbank manuell hinzugefügt haben, als wir sie zum ersten Mal erstellt haben:

Screenshot des Antwortfensters der Anwendung, in dem das /Dinners / Details / 1 U R L rot im Adressfeld eingekreist ist.

Dies bringt uns schnell in Betrieb und bietet uns eine erste Implementierung unserer Detail.aspx-Ansicht. Anschließend können wir sie anpassen, um die Benutzeroberfläche zu unserer Zufriedenheit anzupassen.

Wenn wir uns die Vorlage Details.aspx genauer ansehen, werden wir feststellen, dass sie statisches HTML sowie eingebetteten Renderingcode enthält. <% %> code nuggets führen Code aus, wenn die Ansichtsvorlage gerendert wird, und <%= %> code nuggets führen den darin enthaltenen Code aus und rendern das Ergebnis dann in den Ausgabestream der Vorlage.

Wir können Code in unserer Ansicht schreiben, der auf das "Dinner"-Modellobjekt zugreift, das von unserem Controller mit einer stark typisierten "Model"-Eigenschaft übergeben wurde. Visual Studio stellt beim Zugriff auf diese "Model"-Eigenschaft im Editor den vollständigen Code-Intellisense bereit:

Screenshot des Code-Editor-Fensters mit einer Dropdownliste mit blau hervorgehobenem Element Beschreibung

Lassen Sie uns einige Optimierungen vornehmen, damit die Quelle für unsere letzte Detailansichtsvorlage wie folgt aussieht:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner: <%=Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2><%=Html.Encode(Model.Title) %></h2>
    <p>
        <strong>When:</strong> 
        <%=Model.EventDate.ToShortDateString() %> 

        <strong>@</strong>
        <%=Model.EventDate.ToShortTimeString() %>
    </p>
    <p>
        <strong>Where:</strong> 
        <%=Html.Encode(Model.Address) %>,
        <%=Html.Encode(Model.Country) %>
    </p>
     <p>
        <strong>Description:</strong> 
        <%=Html.Encode(Model.Description) %>
    </p>       
    <p>
        <strong>Organizer:</strong> 
        <%=Html.Encode(Model.HostedBy) %>
        (<%=Html.Encode(Model.ContactPhone) %>)
    </p>
    
    <%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID })%> |
    <%= Html.ActionLink("Delete Dinner","Delete", new { id=Model.DinnerID})%>   
     
</asp:Content>

Wenn wir erneut auf die URL "/Dinners/Details/1" zugreifen, wird sie wie folgt gerendert:

Screenshot des Anwendungsantwortfensters mit der neuen Stilisierung der dot NET Futures-Ansicht

Implementieren der Ansichtsvorlage "Index"

Implementieren wir nun die Ansichtsvorlage "Index", die eine Liste der bevorstehenden Dinner generiert. Dazu positionieren wir den Textcursor in der Index-Aktionsmethode, klicken dann mit der rechten Maustaste, und wählen Sie den Menübefehl "Ansicht hinzufügen" aus (oder drücken Sie STRG-M, STRG-V).

Im Dialogfeld "Ansicht hinzufügen" behalten wir die Ansichtsvorlage "Index" bei und aktivieren das Kontrollkästchen "Stark typisierte Ansicht erstellen". Dieses Mal werden wir eine Vorlage für die Ansicht "Liste" automatisch generieren und "NerdDinner.Models.Dinner" auswählen, da der Modelltyp an die Ansicht übergeben wurde (da wir angegeben haben, dass wir ein Gerüst "Liste" erstellen, wird im Dialogfeld Ansicht hinzufügen davon ausgegangen, dass wir eine Sequenz von Dinner-Objekten von unserem Controller an die Ansicht übergeben):

Screenshot des Fensters Ansicht hinzufügen, in dem der Ansichtsname auf Index festgelegt ist, das Kontrollkästchen Stark typisierte Ansicht erstellen aktiviert ist und das Kontrollkästchen Master Seite auswählen aktiviert ist.

Wenn wir auf die Schaltfläche "Hinzufügen" klicken, erstellt Visual Studio eine neue Vorlagendatei für die Ansicht "Index.aspx" für uns in unserem Verzeichnis "\Views\Dinners". Es "gerüstet" eine anfängliche Implementierung darin, die eine HTML-Tabellenliste der Dinners bereitstellt, die wir an die Ansicht übergeben.

Wenn wir die Anwendung ausführen und auf die URL "/Dinners/" zugreifen, wird die Liste der Abendessen wie folgt gerendert:

Screenshot des Anwendungsantwortfensters mit der Liste der Abendessen in einem Rasterlayout nach dem Update

Die obige Tabellenlösung bietet uns ein rasterartiges Layout unserer Dinner-Daten – was wir uns für unseren Dinner-Eintrag mit Verbraucherseite nicht ganz wünschen. Wir können die Index.aspx-Ansichtsvorlage aktualisieren und so ändern, dass sie weniger Datenspalten auflistet, und verwenden Sie ein <ul-Element> , um sie anstelle einer Tabelle mit dem folgenden Code zu rendern:

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>                 
                <%=Html.Encode(dinner.Title) %>            
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
    
</asp:Content>

Wir verwenden die "var"-Schlüsselwort (keyword) innerhalb der obigen foreach-Anweisung, während wir eine Schleife über jedes Abendessen in unserem Modell ausführen. Diejenigen, die mit C# 3.0 nicht vertraut sind, könnten denken, dass die Verwendung von "var" bedeutet, dass das Dinner-Objekt spät gebunden ist. Dies bedeutet stattdessen, dass der Compiler einen Typrückschluss auf die stark typisierte Eigenschaft "Model" (vom Typ "IEnumerable<Dinner>") verwendet und die lokale "Dinner"-Variable als Dinner-Typ kompiliert– was bedeutet, dass wir eine vollständige Intellisense- und Kompilierzeitüberprüfung dafür in Codeblöcken erhalten:

Screenshot des Code-Editor-Fensters mit einem Dropdownmenü mit hervorgehobenem Adresslistenelement in einem grau gepunkteten Feld.

Wenn wir in unserem Browser auf Aktualisieren für die /Dinners-URL klicken, sieht die aktualisierte Ansicht nun wie folgt aus:

Screenshot des Anwendungsantwortfensters mit einer Liste der bevorstehenden Abendessen nach dem Aktualisierungsbefehl.

Das sieht besser aus – ist aber noch nicht ganz da. Unser letzter Schritt besteht darin, Endbenutzern das Klicken auf einzelne Dinners in der Liste zu ermöglichen und Details darüber anzuzeigen. Dies wird implementiert, indem wir HTML-Linkelemente rendern, die mit der Aktionsmethode Details auf unserem DinnersController verknüpft sind.

Wir können diese Hyperlinks in unserer Indexansicht auf eine von zwei Arten generieren. Die erste besteht darin, manuell HTML-Elemente <> wie unten zu erstellen, wobei %%>-Blöcke in ein <> HTML-Element eingebettet <werden:

Screenshot des Code-Editor-Fensters mit hervorgehobenem und rot eingekreisten Blocktext einer Klasse und prozentualem Block.

Ein alternativer Ansatz, den wir verwenden können, besteht darin, die integrierte Hilfsmethode "Html.ActionLink()" in ASP.NET MVC zu nutzen, die das programmgesteuerte Erstellen eines HTML-Elements <> unterstützt, das mit einer anderen Aktionsmethode auf einem Controller verknüpft ist:

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

Der erste Parameter für die Html.ActionLink()-Hilfsmethode ist der anzuzeigende Link-Text (in diesem Fall der Titel des Dinners), der zweite Parameter ist der Name der Controller-Aktion, zu dem wir den Link generieren möchten (in diesem Fall die Details-Methode), und der dritte Parameter ist ein Satz von Parametern, die an die Aktion gesendet werden sollen (implementiert als anonymer Typ mit Eigenschaftsname/Werten). In diesem Fall geben wir den Parameter "id" des Dinners an, mit dem wir eine Verknüpfung herstellen möchten, und da die Standard-URL-Routingregel in ASP.NET MVC "{Controller}/{Action}/{id}" lautet, generiert die Html.ActionLink()-Hilfsmethode die folgende Ausgabe:

<a href="/Dinners/Details/1">.NET Futures</a>

Für die Index.aspx-Ansicht verwenden wir den Html.ActionLink()-Hilfsmethodenansatz und haben jedes Abendessen im Listenlink zur entsprechenden Detail-URL:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Upcoming Dinners
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>     
                <%=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
</asp:Content>

Und jetzt, wenn wir auf die /Dinners-URL klicken, sieht unsere Dinnerliste wie folgt aus:

Screenshot des Anwendungsantwortfensters, das die liste der bevorstehenden Abendessen mit neuen Links zeigt, die den Listenelementen entsprechen.

Wenn wir auf eines der Dinners in der Liste klicken, navigieren wir, um Details dazu anzuzeigen:

Screenshot des Anwendungsantwortfensters, in dem das ausgewählte Listenelement und die entsprechenden Details angezeigt werden, wie sie in die Datenbank eingegeben wurden.

Konventionsbasierte Benennung und verzeichnisstruktur "\Views"

ASP.NET MVC-Anwendungen verwenden standardmäßig eine konventionsbasierte Verzeichnisnamensstruktur beim Auflösen von Ansichtsvorlagen. Dadurch können Entwickler vermeiden, dass sie einen Standortpfad vollständig qualifizieren müssen, wenn sie auf Ansichten innerhalb einer Controllerklasse verweisen. Standardmäßig sucht ASP.NET MVC im Verzeichnis *\Views[ControllerName]* unterhalb der Anwendung nach der Ansichtsvorlagendatei.

Wir haben beispielsweise an der DinnersController-Klasse gearbeitet, die explizit auf drei Ansichtsvorlagen verweist: "Index", "Details" und "NotFound". ASP.NET MVC sucht standardmäßig im Verzeichnis \Views\Dinners unter unserem Anwendungsstammverzeichnis nach diesen Ansichten:

Screenshot des Fensters

Beachten Sie oben, dass es derzeit drei Controllerklassen innerhalb des Projekts gibt (DinnersController, HomeController und AccountController – die letzten beiden wurden standardmäßig hinzugefügt, als wir das Projekt erstellt haben), und es gibt drei Unterverzeichnisse (eines für jeden Controller) im Verzeichnis \Views.

Ansichten, auf die von den Controllern "Start" und "Konten" verwiesen wird, lösen ihre Ansichtsvorlagen automatisch aus den jeweiligen Verzeichnissen \Views\Home und \Views\Account auf. Das Unterverzeichnis \Views\Shared bietet eine Möglichkeit zum Speichern von Ansichtsvorlagen, die auf mehreren Controllern innerhalb der Anwendung wiederverwendet werden. Wenn ASP.NET MVC versucht, eine Ansichtsvorlage aufzulösen, wird zuerst innerhalb des \ Views[Controller] -spezifischen Verzeichnisses überprüft. Wenn die Ansichtsvorlage dort nicht gefunden werden kann, wird im Verzeichnis \Views\Shared gesucht.

Wenn es um die Benennung einzelner Ansichtsvorlagen geht, wird empfohlen, dass die Ansichtsvorlage den gleichen Namen wie die Aktionsmethode verwendet, die zum Rendern geführt hat. Beispielsweise verwendet unsere Aktionsmethode "Index" die Ansicht "Index", um das Ansichtsergebnis zu rendern, und die Aktionsmethode "Details" verwendet die Ansicht "Details", um ihre Ergebnisse zu rendern. Dadurch können Sie schnell erkennen, welche Vorlage den einzelnen Aktionen zugeordnet ist.

Entwickler müssen den Namen der Ansichtsvorlage nicht explizit angeben, wenn die Ansichtsvorlage denselben Namen hat wie die Aktionsmethode, die auf dem Controller aufgerufen wird. Stattdessen können wir das Modellobjekt einfach an die Hilfsmethode "View()" übergeben (ohne den Ansichtsnamen anzugeben), und ASP.NET MVC leitet automatisch ab, dass wir die Ansichtsvorlage \Views[ControllerName][ActionName] auf dem Datenträger verwenden möchten, um es zu rendern.

Dadurch können wir unseren Controllercode ein wenig sauber und vermeiden, dass der Name zweimal im Code dupliziert wird:

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View(dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }
}

Der obige Code ist alles, was erforderlich ist, um eine schöne Dinner-Auflistung/Details-Erfahrung für die Website zu implementieren.

Nächster Schritt

Wir haben jetzt eine schöne Dinner-Browsing-Erfahrung gebaut.

Jetzt aktivieren wir die Unterstützung für die Bearbeitung von CRUD-Datenformularen (Create, Read, Update, Delete).