Usare controller e visualizzazioni per implementare un'interfaccia utente elenco/dettagli

di Microsoft

Scarica il PDF

Questo è il passaggio 4 di un'esercitazione gratuita sull'applicazione "NerdDinner" che illustra come creare un'applicazione Web di piccole dimensioni, ma completa, usando ASP.NET MVC 1.

Il passaggio 4 illustra come aggiungere un controller all'applicazione che sfrutta il modello per offrire agli utenti un'esperienza di navigazione di presentazione/dettagli dei dati per le cene nel sito NerdDinner.

Se si usa ASP.NET MVC 3, è consigliabile seguire le esercitazioni Introduzione Con MVC 3 o MVC Music Store.

NerdDinner Passaggio 4: Controller e visualizzazioni

Con i framework Web tradizionali (ASP classico, PHP, Web Forms ASP.NET e così via), gli URL in ingresso vengono in genere mappati ai file su disco. Ad esempio, una richiesta per un URL come "/Products.aspx" o "/Products.php" potrebbe essere elaborata da un file "Products.aspx" o "Products.php".

I framework MVC basati sul Web eseguono il mapping degli URL al codice del server in modo leggermente diverso. Anziché eseguire il mapping degli URL in ingresso ai file, esegue invece il mapping degli URL ai metodi nelle classi. Queste classi sono denominate "Controller" e sono responsabili dell'elaborazione delle richieste HTTP in ingresso, della gestione dell'input dell'utente, del recupero e del salvataggio dei dati e della determinazione della risposta da inviare al client (visualizzare HTML, scaricare un file, reindirizzare a un URL diverso e così via).

Ora che è stato creato un modello di base per l'applicazione NerdDinner, il passaggio successivo consiste nell'aggiungere un controller all'applicazione che ne trae vantaggio per fornire agli utenti un'esperienza di navigazione di presentazione/dettagli dei dati per Le cene nel nostro sito.

Aggiunta di un controller DinnersController

Si inizierà facendo clic con il pulsante destro del mouse sulla cartella "Controller" all'interno del progetto Web e quindi selezionando il comando di menu Aggiungi> controller (è anche possibile eseguire questo comando digitando CTRL-M, CTRL-C):

Screenshot della finestra Esplora soluzioni che mostra la cartella Controllers e le voci di menu Aggiungi e controller evidenziate in blu.

Verrà visualizzata la finestra di dialogo "Aggiungi controller":

Screenshot della finestra di dialogo Aggiungi controller che mostra il campo Nome controller compilato con il testo Dinners Controller.

Il nuovo controller sarà "DinnersController" e fare clic sul pulsante "Aggiungi". Visual Studio aggiungerà quindi un file DinnersController.cs nella directory \Controllers:

Screenshot della finestra Esplora soluzioni che mostra il file Dinner Controllers dot c s evidenziato in blu.

Verrà aperta anche la nuova classe DinnersController all'interno dell'editor di codice.

Aggiunta di metodi di azione Index() e Details() alla classe DinnersController

Si vuole consentire ai visitatori di usare l'applicazione per visualizzare un elenco di cene imminenti e consentire loro di fare clic su qualsiasi cena nell'elenco per visualizzare dettagli specifici su di esso. Questa operazione verrà eseguita pubblicando gli URL seguenti dall'applicazione:

URL Scopo
/Cene/ Visualizzare un elenco HTML delle prossime cene
/Dinners/Details/[id] Visualizzare i dettagli relativi a una cena specifica indicata da un parametro "id" incorporato nell'URL, che corrisponderà all'ID Cena della cena nel database. Ad esempio: /Dinners/Details/2 visualizzerebbe una pagina HTML con i dettagli sulla cena il cui valore DinnerID è 2.

Verranno pubblicate le implementazioni iniziali di questi URL aggiungendo due "metodi di azione" pubblici alla classe DinnersController, come illustrato di seguito:

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>");
    }
}

Si eseguirà quindi l'applicazione NerdDinner e si userà il browser per richiamarli. La digitazione nell'URL "/Dinners/" causerà l'esecuzione del metodo Index() e restituirà la risposta seguente:

Screenshot della finestra di risposta generata dall'esecuzione dell'applicazione NerdDinner, che mostra il testo Presto disponibile: Dinners.

Se si digita l'URL "/Dinners/Details/2", il metodo Details() verrà eseguito e verrà restituita la risposta seguente:

Screenshot della finestra di risposta generata dall'esecuzione dell'applicazione NerdDinner, che mostra il testo Details Dinner I D: 2.

Ci si potrebbe chiedere : in che modo ASP.NET MVC sa creare la classe DinnersController e richiamare tali metodi? Per comprendere il funzionamento del routing, è necessario esaminare rapidamente il funzionamento del routing.

Informazioni sul routing MVC ASP.NET

ASP.NET MVC include un potente motore di routing degli URL che offre una notevole flessibilità nel controllo del mapping degli URL alle classi controller. Consente di personalizzare completamente il modo in cui ASP.NET MVC sceglie la classe controller da creare, quale metodo richiamare su di esso, nonché configurare diversi modi in cui le variabili possono essere analizzate automaticamente dall'URL/Querystring e passate al metodo come argomenti di parametro. Offre la flessibilità necessaria per ottimizzare completamente un sito per SEO (ottimizzazione del motore di ricerca) e pubblicare qualsiasi struttura di URL desiderata da un'applicazione.

Per impostazione predefinita, i nuovi progetti MVC ASP.NET sono dotati di un set preconfigurato di regole di routing URL già registrate. In questo modo è possibile iniziare facilmente a usare un'applicazione senza dover configurare in modo esplicito alcun elemento. Le registrazioni predefinite delle regole di routing sono disponibili nella classe "Application" dei progetti, che è possibile aprire facendo doppio clic sul file "Global.asax" nella radice del progetto:

Screenshot della finestra Esplora soluzioni che mostra il punto globale un file x evidenziato in blu e cerchiato in rosso.

Le regole di routing MVC predefinite ASP.NET vengono registrate nel metodo "RegisterRoutes" di questa classe:

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
    );
}

Le "route. La chiamata al metodo MapRoute()" precedente registra una regola di routing predefinita che esegue il mapping degli URL in ingresso alle classi controller usando il formato URL: "/{controller}/{action}/{id}", dove "controller" è il nome della classe controller per creare un'istanza, "action" è il nome di un metodo pubblico da richiamare su di esso e "id" è un parametro facoltativo incorporato all'interno dell'URL che può essere passato come argomento al metodo. Il terzo parametro passato alla chiamata al metodo "MapRoute()" è un set di valori predefiniti da usare per i valori controller/action/id nel caso in cui non siano presenti nell'URL (Controller = "Home", Action="Index", Id="").

Di seguito è riportata una tabella che illustra come viene eseguito il mapping di un'ampia gamma di URL usando la regola di route predefinita "/{controllers}/{action}/{id}":

URL Classe controller Metodo Azione Parametri passati
/Dinners/Details/2 DinnersController Details(id) id=2
/Dinners/Edit/5 DinnersController Edit(id) id=5
/Dinners/Create DinnersController Create() N/D
/Cene DinnersController Index() N/D
/Casa Homecontroller Index() N/D
/ Homecontroller Index() N/D

Le ultime tre righe mostrano i valori predefiniti (Controller = Home, Action = Index, Id = "") usati. Poiché il metodo "Index" viene registrato come nome di azione predefinito se non ne viene specificato uno, gli URL "/Dinners" e "/Home" fanno sì che il metodo di azione Index() venga richiamato nelle relative classi controller. Poiché il controller "Home" viene registrato come controller predefinito se non ne viene specificato uno, l'URL "/" fa sì che venga creato HomeController e che venga richiamato il metodo di azione Index().

Se non si preferisce queste regole di routing degli URL predefinite, la buona notizia è che sono facili da modificare. È sufficiente modificarle all'interno del metodo RegisterRoutes precedente. Per l'applicazione NerdDinner, tuttavia, non verranno modificate le regole di routing degli URL predefinite, ma verranno usate così com'è.

Uso di DinnerRepository dal nostro DinnersController

Sostituire ora l'implementazione corrente dei metodi di azione Index() e Details() di DinnersController con implementazioni che usano il modello.

Verrà usata la classe DinnerRepository creata in precedenza per implementare il comportamento. Si inizierà aggiungendo un'istruzione "using" che fa riferimento allo spazio dei nomi "NerdDinner.Models" e quindi dichiarando un'istanza di DinnerRepository come campo nella classe DinnerController.

Più avanti in questo capitolo verrà presentato il concetto di "Inserimento delle dipendenze" e verrà illustrato un altro modo per consentire ai controller di ottenere un riferimento a un oggetto DinnerRepository che consente un test unità migliore, ma per il momento si creerà solo un'istanza dell'inline DinnerRepository come illustrato di seguito.

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);
        }
    }
}

A questo momento è possibile generare una risposta HTML usando gli oggetti del modello di dati recuperati.

Uso delle visualizzazioni con il controller

Anche se è possibile scrivere codice all'interno dei metodi di azione per assemblare HTML e quindi usare il metodo helper Response.Write() per inviarlo al client, questo approccio diventa piuttosto difficile rapidamente. Un approccio molto migliore consiste nell'eseguire solo l'applicazione e la logica dei dati all'interno dei metodi di azione DinnersController e quindi passare i dati necessari per eseguire il rendering di una risposta HTML a un modello di "visualizzazione" separato responsabile dell'output della relativa rappresentazione HTML. Come vedremo in un momento, un modello di "visualizzazione" è un file di testo che in genere contiene una combinazione di markup HTML e codice di rendering incorporato.

La separazione della logica del controller dal rendering della visualizzazione offre numerosi vantaggi. In particolare, consente di applicare una chiara "separazione delle preoccupazioni" tra il codice dell'applicazione e la formattazione/rendering dell'interfaccia utente. In questo modo è molto più semplice eseguire unit test della logica dell'applicazione in isolamento dalla logica di rendering dell'interfaccia utente. Semplifica la modifica dei modelli di rendering dell'interfaccia utente senza dover apportare modifiche al codice dell'applicazione. E può semplificare la collaborazione tra sviluppatori e progettisti sui progetti.

È possibile aggiornare la classe DinnersController per indicare che si vuole usare un modello di visualizzazione per inviare una risposta dell'interfaccia utente HTML modificando le firme del metodo dei due metodi di azione, dalla presenza di un tipo restituito "void" al tipo restituito "ActionResult". È quindi possibile chiamare il metodo helper View() nella classe base Controller per restituire un oggetto "ViewResult" simile al seguente:

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);
    }
}

La firma del metodo helper View() in uso sopra è simile alla seguente:

Screenshot del metodo helper View con il testo View Result View (Nome visualizzazione stringa, modello a oggetti).

Il primo parametro del metodo helper View() è il nome del file modello di visualizzazione che si vuole usare per eseguire il rendering della risposta HTML. Il secondo parametro è un oggetto modello che contiene i dati necessari al modello di visualizzazione per eseguire il rendering della risposta HTML.

All'interno del metodo di azione Index() viene chiamato il metodo helper View() e viene indicato che si vuole eseguire il rendering di un elenco HTML delle cene usando un modello di visualizzazione "Index". Il modello di visualizzazione viene passato a una sequenza di oggetti Dinner da cui generare l'elenco:

//
    // GET: /Dinners/

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

All'interno del metodo di azione Details() si tenta di recuperare un oggetto Dinner usando l'ID fornito all'interno dell'URL. Se viene trovata una cena valida, viene chiamato il metodo helper View(), che indica che si vuole usare un modello di visualizzazione "Dettagli" per eseguire il rendering dell'oggetto Dinner recuperato. Se viene richiesta una cena non valida, viene visualizzato un messaggio di errore utile che indica che dinner non esiste usando un modello di visualizzazione "NotFound" (e una versione di overload del metodo helper View() che accetta solo il nome del modello:

//
    // 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);
    }

Verranno ora implementati i modelli di visualizzazione "NotFound", "Details" e "Index".

Implementazione del modello di visualizzazione "NotFound"

Si inizierà implementando il modello di visualizzazione "NotFound", che visualizza un messaggio di errore descrittivo che indica che non è possibile trovare la cena richiesta.

Verrà creato un nuovo modello di visualizzazione posizionando il cursore di testo all'interno di un metodo di azione del controller, quindi fare clic con il pulsante destro del mouse e scegliere il comando di menu "Aggiungi visualizzazione" (è anche possibile eseguire questo comando digitando CTRL-M, CTRL-V):

Screenshot del progetto con la voce di menu Aggiungi visualizzazione evidenziata in blu e cerchiata in rosso.

Verrà visualizzata una finestra di dialogo "Aggiungi visualizzazione" come illustrato di seguito. Per impostazione predefinita, la finestra di dialogo prepopocherà il nome della visualizzazione per creare in modo che corrisponda al nome del metodo di azione in cui si trovava il cursore al momento dell'avvio della finestra di dialogo (in questo caso "Dettagli"). Poiché si vuole prima implementare il modello "NotFound", si eseguirà l'override di questo nome di visualizzazione e verrà impostato su "NotFound":

Screenshot della finestra Aggiungi visualizzazione con il campo Nome visualizzazione impostato su Non trovato, la casella Seleziona pagina master selezionata e il Segnaposto contenuto I D impostato su Contenuto principale.

Quando si fa clic sul pulsante "Aggiungi", Visual Studio creerà un nuovo modello di visualizzazione "NotFound.aspx" all'interno della directory "\Views\Dinners", che verrà creata anche se la directory non esiste già:

Screenshot della gerarchia di cartelle della finestra di Esplora soluzioni con il punto Not Found di un file s p x evidenziato in blu.

Verrà aperto anche il nuovo modello di visualizzazione "NotFound.aspx" all'interno dell'editor di codice:

Screenshot della finestra dell'editor di codice con il punto Not Found a s p x file aperto nell'editor di codice.

Per impostazione predefinita, i modelli di visualizzazione hanno due "aree di contenuto" in cui è possibile aggiungere contenuto e codice. Il primo consente di personalizzare il "titolo" della pagina HTML restituita. Il secondo consente di personalizzare il "contenuto principale" della pagina HTML inviata di nuovo.

Per implementare il modello di visualizzazione "NotFound" aggiungeremo alcuni contenuti di base:

<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>

È quindi possibile provarlo all'interno del browser. A tale scopo, richiedere l'URL "/Dinners/Details/9999". Questo farà riferimento a una cena che non esiste attualmente nel database e causerà il rendering del modello di visualizzazione "NotFound" del metodo di azione DinnersController.Details():

Screenshot della finestra My MVC Application (Applicazione MVC personale) con /Dinners/Details / 9999 U R L nella casella degli indirizzi in rosso.

Una cosa che noterai nella schermata precedente è che il modello di visualizzazione di base ha ereditato un gruppo di HTML che circonda il contenuto principale sullo schermo. Questo perché il modello di visualizzazione usa un modello di "pagina master" che consente di applicare un layout coerente in tutte le visualizzazioni del sito. Verrà illustrato come funzionano più avanti le pagine master in una parte successiva di questa esercitazione.

Implementazione del modello di visualizzazione "Dettagli"

Verrà ora implementato il modello di visualizzazione "Dettagli", che genererà il codice HTML per un singolo modello Dinner.

A tale scopo, posizionare il cursore di testo all'interno del metodo di azione Dettagli, quindi fare clic con il pulsante destro del mouse e scegliere il comando di menu "Aggiungi visualizzazione" (o premere CTRL-M, CTRL-V):

Screenshot della finestra dell'editor di codice che mostra la voce di menu Aggiungi punto punto di visualizzazione evidenziato in rosso.

Verrà visualizzata la finestra di dialogo "Aggiungi visualizzazione". Il nome di visualizzazione predefinito ("Dettagli") verrà mantenuto. Selezionare anche la casella di controllo "Crea una visualizzazione fortemente tipizzata" nella finestra di dialogo e selezionare (usando l'elenco a discesa casella combinata) il nome del tipo di modello passato dal controller alla visualizzazione. Per questa visualizzazione viene passato un oggetto Dinner (il nome completo per questo tipo è: "NerdDinner.Models.Dinner"):

Screenshot of the Add View window with the View content dropdown set to Details and the View data class set to Nerd Dinner dot Models dot Dinner.

A differenza del modello precedente, in cui si è scelto di creare una "Visualizzazione vuota", questa volta si sceglie di "eseguire automaticamente lo scaffolding" della visualizzazione usando un modello "Dettagli". È possibile indicare questo valore modificando l'elenco a discesa "Visualizza contenuto" nella finestra di dialogo precedente.

"Scaffolding" genererà un'implementazione iniziale del modello di visualizzazione dei dettagli in base all'oggetto Dinner che viene passato. In questo modo è possibile iniziare rapidamente a usare l'implementazione del modello di visualizzazione.

Quando si fa clic sul pulsante "Aggiungi", Visual Studio creerà un nuovo file modello di visualizzazione "Details.aspx" all'interno della directory "\Views\Dinners":

Screenshot della finestra Esplora soluzioni che mostra la gerarchia di cartelle con la cartella Dinners evidenziata in blu.

Verrà anche aperto il nuovo modello di visualizzazione "Details.aspx" all'interno dell'editor di codice. Conterrà un'implementazione iniziale dello scaffolding di una visualizzazione dei dettagli basata su un modello Dinner. Il motore di scaffolding usa la reflection .NET per esaminare le proprietà pubbliche esposte sulla classe passata e aggiungerà contenuto appropriato in base a ogni tipo trovato:

<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>

È possibile richiedere l'URL "/Dinners/Details/1" per visualizzare l'aspetto dell'implementazione dello scaffold "details" nel browser. Con questo URL verrà visualizzata una delle cene aggiunte manualmente al database al momento della creazione:

Screenshot della finestra di risposta dell'applicazione che mostra / Dinners / Details / 1 U R L cerchiata in rosso nella casella dell'indirizzo.

In questo modo è possibile eseguire rapidamente e offre un'implementazione iniziale della visualizzazione Details.aspx. È quindi possibile modificarla per personalizzare l'interfaccia utente in base alla soddisfazione.

Quando si esamina più attentamente il modello Details.aspx, si scoprirà che contiene codice HTML statico e codice di rendering incorporato. <% %> code nuggets execute code when the view template renders, and <%= %> code nuggets execute the code contained them and then render the result to the output stream of the template.

È possibile scrivere codice all'interno della visualizzazione che accede all'oggetto modello "Dinner" passato dal controller usando una proprietà "Model" fortemente tipizzata. Visual Studio offre codice intelliSense completo quando si accede a questa proprietà "Model" all'interno dell'editor:

Screenshot della finestra dell'editor di codice che mostra un elenco a discesa con la descrizione dell'elemento evidenziata in blu.

Verranno ora apportate alcune modifiche in modo che l'origine per il modello di visualizzazione Dettagli finale sia simile alla seguente:

<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>

Quando si accede nuovamente all'URL "/Dinners/Details/1", il rendering sarà simile al seguente:

Screenshot della finestra di risposta dell'applicazione che mostra la nuova stilizzazione della visualizzazione Futures dot NET.

Implementazione del modello di visualizzazione "Index"

A questo punto si implementa il modello di visualizzazione "Indice", che genererà un elenco delle prossime cene. A tale scopo, il cursore di testo verrà posizionato all'interno del metodo di azione Indice, quindi fare clic con il pulsante destro del mouse e scegliere il comando di menu "Aggiungi visualizzazione" (oppure premere CTRL-M, CTRL-V).

Nella finestra di dialogo "Aggiungi visualizzazione" si manterrà il modello di visualizzazione denominato "Index" e si seleziona la casella di controllo "Crea una visualizzazione fortemente tipizzata". Questa volta si sceglie di generare automaticamente un modello di visualizzazione "Elenco" e selezionare "NerdDinner.Models.Dinner" come tipo di modello passato alla visualizzazione (che perché è stato indicato che si sta creando uno scaffolding "Elenco" causerà il passaggio di una sequenza di oggetti Dinner dal controller alla visualizzazione):

Screenshot della finestra Aggiungi visualizzazione con il nome visualizzazione impostato su Indice, la casella Crea una visualizzazione fortemente tipizzata selezionata e la casella Seleziona pagina master selezionata.

Quando si fa clic sul pulsante "Aggiungi", Visual Studio creerà un nuovo file modello di visualizzazione "Index.aspx" all'interno della directory "\Views\Dinners". Verrà "scaffolding" un'implementazione iniziale all'interno di essa che fornisce un elenco di tabelle HTML delle cene passate alla visualizzazione.

Quando si esegue l'applicazione e si accede all'URL "/Dinners/" verrà eseguito il rendering dell'elenco delle cene in questo modo:

Screenshot della finestra di risposta dell'applicazione che mostra l'elenco delle cene in un layout griglia dopo l'aggiornamento aggiungi visualizzazione.

La soluzione di tabella precedente offre un layout simile alla griglia dei dati dinner, che non è proprio quello che vogliamo per il nostro consumer che si trova a cena. È possibile aggiornare il modello di visualizzazione Index.aspx e modificarlo per elencare meno colonne di dati e usare un <elemento ul> per eseguirne il rendering anziché una tabella usando il codice seguente:

<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>

Viene usata la parola chiave "var" all'interno dell'istruzione foreach precedente durante il ciclo di ogni cena nel modello. Coloro che non hanno familiarità con C# 3.0 potrebbero pensare che l'uso di "var" significa che l'oggetto dinner è associato in ritardo. Significa invece che il compilatore usa l'inferenza del tipo rispetto alla proprietà "Model" fortemente tipizzata (che è di tipo "IEnumerable<Dinner>") e compila la variabile "dinner" locale come tipo Dinner, ovvero si ottiene il controllo completo intellisense e il controllo in fase di compilazione per esso all'interno di blocchi di codice:

Screenshot della finestra dell'editor di codice che mostra un menu a discesa con la voce di elenco Indirizzi evidenziata in una casella punteggiata grigia.

Quando si raggiunge l'aggiornamento nell'URL /Dinners nel browser, la visualizzazione aggiornata è ora simile alla seguente:

Screenshot della finestra di risposta dell'applicazione che mostra un elenco di cene future dopo il comando di aggiornamento.

Questo aspetto è migliore, ma non è ancora completamente lì. L'ultimo passaggio consiste nell'consentire agli utenti finali di fare clic su singole cene nell'elenco e visualizzare i dettagli su di essi. Questa operazione verrà implementata eseguendo il rendering degli elementi del collegamento ipertestuale HTML che si collegano al metodo di azione Details sul nostro DinnersController.

È possibile generare questi collegamenti ipertestuali all'interno della visualizzazione Indice in uno dei due modi seguenti. Il primo consiste nel creare manualmente un elemento HTML <come quello riportato di seguito, in cui vengono incorporati <%> blocchi all'interno di <un> elemento HTML:>

Screenshot della finestra dell'editor di codice con il testo della classe e del blocco percentuale evidenziato e cerchiato in rosso.

Un approccio alternativo che è possibile usare consiste nel sfruttare il metodo helper "Html.ActionLink()" predefinito all'interno di ASP.NET MVC che supporta la creazione a livello di codice di un> elemento HTML <che collega a un altro metodo di azione in un controller:

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

Il primo parametro del metodo helper Html.ActionLink() è il testo del collegamento da visualizzare (in questo caso il titolo della cena), il secondo parametro è il nome dell'azione controller a cui si vuole generare il collegamento (in questo caso il metodo Details) e il terzo parametro è un set di parametri da inviare all'azione (implementato come tipo anonimo con nome/valori di proprietà). In questo caso si specifica il parametro "id" della cena a cui si vuole eseguire il collegamento e poiché la regola di routing dell'URL predefinita in ASP.NET MVC è "{Controller}/{Action}/{id}" il metodo helper Html.ActionLink() genererà l'output seguente:

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

Per la visualizzazione Index.aspx si userà l'approccio helper Html.ActionLink() e si otterrà ogni cena nel collegamento all'URL dei dettagli appropriato:

<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>

E ora quando si raggiunge l'URL /Dinners l'elenco delle cene è simile al seguente:

Screenshot della finestra di risposta dell'applicazione che mostra l'elenco delle cene imminenti con nuovi collegamenti corrispondenti alle voci dell'elenco.

Quando si fa clic su una delle cene nell'elenco, si passerà per visualizzare i dettagli su di esso:

Screenshot della finestra di risposta dell'applicazione che mostra la voce di elenco selezionata e i dettagli corrispondenti a esso immessi nel database.

Denominazione basata su convenzioni e struttura di directory \Views

ASP.NET applicazioni MVC per impostazione predefinita usano una struttura di denominazione di directory basata su convenzioni durante la risoluzione dei modelli di visualizzazione. Ciò consente agli sviluppatori di evitare di dover qualificare completamente un percorso di posizione quando si fa riferimento alle visualizzazioni dall'interno di una classe Controller. Per impostazione predefinita, ASP.NET MVC cercherà il file del modello di visualizzazione all'interno della directory *\Views[ControllerName]* sotto l'applicazione.

Ad esempio, stiamo lavorando alla classe DinnersController, che fa riferimento in modo esplicito a tre modelli di visualizzazione: "Index", "Details" e "NotFound". ASP.NET MVC cercherà per impostazione predefinita queste visualizzazioni all'interno della directory \Views\Dinners sotto la directory radice dell'applicazione:

Screenshot della finestra Esplora soluzioni che mostra la gerarchia di cartelle con la cartella Dinners evidenziata in un rettangolo blu.

Si noti che attualmente sono presenti tre classi controller all'interno del progetto (DinnersController, HomeController e AccountController, le ultime due sono state aggiunte per impostazione predefinita al momento della creazione del progetto) e sono presenti tre sottodirectory (una per ogni controller) all'interno della directory \Views.

Le visualizzazioni a cui si fa riferimento dai controller Home e Accounts risolveranno automaticamente i modelli di visualizzazione dalle rispettive directory \Views\Home e \Views\Account . La sottodirectory \Views\Shared consente di archiviare i modelli di visualizzazione che vengono riutilizzati tra più controller all'interno dell'applicazione. Quando ASP.NET MVC tenta di risolvere un modello di visualizzazione, verifica prima di tutto nella directory specifica \Views[Controller] e, se non riesce a trovare il modello di visualizzazione, verrà esaminato nella directory \Views\Shared .

Quando si tratta di assegnare un nome ai singoli modelli di visualizzazione, le indicazioni consigliate sono la condivisione del modello di visualizzazione con lo stesso nome del metodo di azione che ne ha causato il rendering. Ad esempio, sopra il metodo di azione "Index" viene usata la visualizzazione "Index" per eseguire il rendering del risultato della visualizzazione e il metodo di azione "Dettagli" usa la visualizzazione "Dettagli" per eseguire il rendering dei risultati. Ciò semplifica la visualizzazione rapida del modello associato a ogni azione.

Gli sviluppatori non devono specificare in modo esplicito il nome del modello di visualizzazione quando il modello di visualizzazione ha lo stesso nome del metodo di azione richiamato nel controller. È invece possibile passare l'oggetto modello al metodo helper "View()" (senza specificare il nome della visualizzazione) e ASP.NET MVC dedurrà automaticamente che si vuole usare il modello di visualizzazione \Views[ControllerName][ActionName] sul disco per eseguirne il rendering.

In questo modo è possibile pulire leggermente il codice del controller ed evitare di duplicare il nome due volte nel codice:

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);
    }
}

Il codice precedente è tutto ciò che è necessario per implementare un'esperienza di presentazione/dettagli della cena piacevole per il sito.

passaggio successivo

Ora abbiamo una bella esperienza di navigazione cena costruito.

A questo punto è possibile abilitare il supporto per la modifica dei moduli dati CRUD (Create, Read, Update, Delete).