Cerca

Nota

Una versione aggiornata di questa esercitazione è disponibile qui usando la versione più recente di Visual Studio. La nuova esercitazione usa ASP.NET Core MVC, che offre molti miglioramenti in questa esercitazione.

Questa esercitazione illustra ASP.NET Core MVC con i controller e le viste. Razor Pages è una nuova alternativa in ASP.NET Core, un modello di programmazione basato su pagine che semplifica e rende più produttiva la creazione dell'interfaccia utente Web. È consigliabile provare l'esercitazione sulle pagine Razor prima della versione MVC. L'esercitazione sulle pagine Razor:

  • È più semplice da seguire.
  • Riguarda più funzionalità.
  • È l'approccio preferito per lo sviluppo di nuove app.

Aggiunta di un metodo di ricerca e di una visualizzazione di ricerca

In questa sezione si aggiungerà la funzionalità di ricerca al Index metodo di azione che consente di cercare film in base al genere o al nome.

Prerequisiti

Per trovare le corrispondenze con le schermate di questa sezione, è necessario eseguire l'applicazione (F5) e aggiungere i film seguenti al database.

Titolo Data di rilascio Genre Prezzo
Ghostbusters 6/8/1984 Commedia 6,99
Ghostbusters II 6/16/1989 Commedia 6,99
Pianeta delle scimmie 3/27/1986 Azione 5,99

Aggiornamento del modulo indice

Per iniziare, aggiornare il Index metodo di azione alla classe esistente MoviesController . Ecco il codice:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

La prima riga del Index metodo crea la query LINQ seguente per selezionare i film:

var movies = from m in db.Movies 
                 select m;

La query viene definita a questo punto, ma non è ancora stata eseguita nel database.

Se il searchString parametro contiene una stringa, la query movies viene modificata per filtrare il valore della stringa di ricerca, usando il codice seguente:

if (!String.IsNullOrEmpty(searchString)) 
{ 
    movies = movies.Where(s => s.Title.Contains(searchString)); 
}

Il codice s => s.Title precedente è un'espressione lambda. Le espressioni lambda vengono usate nelle query LINQ basate su metodo come argomenti per metodi dell'operatore di query standard, ad esempio il metodo Where usato nel codice precedente. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo come Where o OrderBy. Al contrario, l'esecuzione di query viene posticipata, il che significa che la valutazione di un'espressione viene posticipata fino a quando il relativo valore realizzato non viene effettivamente eseguito l'iterazione o viene chiamato il ToList metodo . Nell'esempio Search la query viene eseguita nella vista Index.cshtml . Per altre informazioni sull'esecuzione posticipata di query, vedere Esecuzione di query.

Nota

Il metodo Contains viene eseguito nel database, non nel codice c# precedente. Nel database contiene il mapping a SQL LIKE, senza distinzione tra maiuscole e minuscole.

È ora possibile aggiornare la Index visualizzazione che visualizzerà il modulo all'utente.

Eseguire l'applicazione e passare a /Movies/Index. Accodare una stringa di query, ad esempio ?searchString=ghost, all'URL. Vengono visualizzati i film filtrati.

SearchQryStr

Se si modifica la firma del Index metodo in modo che abbia un parametro denominato id, il id parametro corrisponderà al {id} segnaposto per le route predefinite impostate nel file App_Start\RouteConfig.cs .

{controller}/{action}/{id}

Il metodo originale Index è simile al seguente:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

Il metodo modificato Index sarà simile al seguente:

public ActionResult Index(string id) 
{ 
    string searchString = id; 
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

È ora possibile passare il titolo della ricerca come dati di route (un segmento di URL), anziché come valore della stringa di query.

Screenshot che mostra la pagina M V C Movie Index. I due punti host locali 1 2 3 4 4 barre Film indice barra barra fantasma è nel campo U R L e cerchiato in rosso.

Tuttavia, non è possibile supporre che gli utenti modifichino l'URL ogni volta che desiderano cercare un film. A questo punto si aggiungerà l'interfaccia utente per filtrare i film. Se è stata modificata la firma del Index metodo per verificare come passare il parametro ID associato a route, modificarla di nuovo in modo che il Index metodo accetta un parametro stringa denominato searchString:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

Aprire il file Views\Movies\Index.cshtml e subito dopo @Html.ActionLink("Create New", "Create"), aggiungere il markup del modulo evidenziato di seguito:

@model IEnumerable<MvcMovie.Models.Movie> 
 
@{ 
    ViewBag.Title = "Index"; 
} 
 
<h2>Index</h2> 
 
<p> 
    @Html.ActionLink("Create New", "Create") 
     
     @using (Html.BeginForm()){    
         <p> Title: @Html.TextBox("SearchString") <br />   
         <input type="submit" value="Filter" /></p> 
        } 
</p>

L'helper Html.BeginForm crea un tag di apertura <form> . L'helper Html.BeginForm fa sì che il modulo invii se stesso quando l'utente invia il modulo facendo clic sul pulsante Filtro .

Visual Studio 2013 offre un buon miglioramento durante la visualizzazione e la modifica dei file di visualizzazione. Quando si esegue l'applicazione con un file di visualizzazione aperto, Visual Studio 2013 richiama il metodo di azione del controller corretto per visualizzare la visualizzazione.

Screenshot che mostra la scheda Index dot c s h t m l e Esplora soluzioni aperta. In Esplora soluzioni la sottocartella Movies è aperta e l'opzione Index dot c s h t l è selezionata.

Con la visualizzazione Indice aperta in Visual Studio (come illustrato nell'immagine precedente), toccare Ctr F5 o F5 per eseguire l'applicazione e quindi provare a cercare un filmato.

Screenshot che mostra la pagina Indice con un titolo immesso nel campo Titolo.

Non esiste alcun HttpPost overload del Index metodo . Non è necessario, perché il metodo non modifica lo stato dell'applicazione, filtrando semplicemente i dati.

È possibile aggiungere il metodo HttpPost Index seguente. In tal caso, l'action invoker corrisponde al HttpPost Index metodo e il HttpPost Index metodo verrebbe eseguito come illustrato nell'immagine seguente.

[HttpPost] 
public string Index(FormCollection fc, string searchString) 
{ 
    return "<h3> From [HttpPost]Index: " + searchString + "</h3>"; 
}

SearchPostGhost

Tuttavia, anche se si aggiunge questa versione HttpPost del metodo Index, esiste una limitazione sul modo sulla relativa implementazione. Si supponga che si desideri usare come segnalibro una ricerca specifica o inviare un collegamento agli amici su cui possono fare clic per visualizzare lo stesso elenco filtrato di film. Si noti che l'URL per la richiesta HTTP POST corrisponde all'URL della richiesta GET (localhost:xxxxx/Movies/Index). Non sono presenti informazioni di ricerca nell'URL stesso. Al momento, le informazioni sulla stringa di ricerca vengono inviate al server come valore del campo modulo. Ciò significa che non è possibile acquisire le informazioni di ricerca nel segnalibro o inviarle agli amici in un URL.

La soluzione consiste nell'usare un overload di BeginForm che specifica che la richiesta POST deve aggiungere le informazioni di ricerca all'URL e che deve essere indirizzata alla HttpGet versione del Index metodo . Sostituire il metodo senza BeginForm parametri esistente con il markup seguente:

@using (Html.BeginForm("Index","Movies",FormMethod.Get))

BeginFormPost_SM

Ora, quando si invia una ricerca, l'URL contiene una stringa di query di ricerca. La ricerca passerà anche al metodo di azione HttpGet Index, anche se si dispone di un metodo HttpPost Index.

IndexWithGetURL

Aggiunta della ricerca per genere

Se è stata aggiunta la HttpPost versione del Index metodo, eliminarla ora.

Successivamente, si aggiungerà una funzionalità per consentire agli utenti di cercare film per genere. Sostituire il metodo Index con il codice seguente:

public ActionResult Index(string movieGenre, string searchString)
{
    var GenreLst = new List<string>();

    var GenreQry = from d in db.Movies
                   orderby d.Genre
                   select d.Genre;

    GenreLst.AddRange(GenreQry.Distinct());
    ViewBag.movieGenre = new SelectList(GenreLst);

    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (!string.IsNullOrEmpty(movieGenre))
    {
        movies = movies.Where(x => x.Genre == movieGenre);
    }

    return View(movies);
}

Questa versione del Index metodo accetta un parametro aggiuntivo, ovvero movieGenre. Le prime righe di codice creano un List oggetto per contenere generi cinematografici dal database.

Il codice seguente è una query LINQ che recupera tutti i generi dal database.

var GenreQry = from d in db.Movies 
                   orderby d.Genre 
                   select d.Genre;

Il codice usa il AddRange metodo della raccolta generica List per aggiungere tutti i generi distinti all'elenco. (Senza il Distinct modificatore, i generi duplicati verrebbero aggiunti, ad esempio, la commedia verrebbe aggiunta due volte nell'esempio). Il codice archivia quindi l'elenco di generi nell'oggetto ViewBag.MovieGenre . L'archiviazione dei dati delle categorie (ad esempio generi di film) come oggetto SelectList in un ViewBagoggetto , quindi l'accesso ai dati delle categorie in una casella di riepilogo a discesa è un approccio tipico per le applicazioni MVC.

Nel codice seguente viene illustrato come controllare il movieGenre parametro . Se non è vuoto, il codice vincola ulteriormente la query movies per limitare i film selezionati al genere specificato.

if (!string.IsNullOrEmpty(movieGenre))
{
    movies = movies.Where(x => x.Genre == movieGenre);
}

Come indicato in precedenza, la query non viene eseguita nel database fino a quando l'elenco di film non viene sottoposto a iterazione (che si verifica nella visualizzazione, dopo che il Index metodo azione viene restituito).

Aggiunta di markup alla visualizzazione indice per supportare la ricerca per genere

Aggiungere un Html.DropDownList helper al file Views\Movies\Index.cshtml , subito prima dell'helper TextBox . Il markup completato è illustrato di seguito:

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="table">

Nel codice seguente:

@Html.DropDownList("movieGenre", "All")

Il parametro "MovieGenre" fornisce la chiave per l'helper DropDownList per trovare un IEnumerable<SelectListItem> oggetto in ViewBag. L'oggetto ViewBag è stato popolato nel metodo azione:

public ActionResult Index(string movieGenre, string searchString)
{
    var GenreLst = new List<string>();

    var GenreQry = from d in db.Movies
                   orderby d.Genre
                   select d.Genre;

    GenreLst.AddRange(GenreQry.Distinct());
    ViewBag.movieGenre = new SelectList(GenreLst);

    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (!string.IsNullOrEmpty(movieGenre))
    {
        movies = movies.Where(x => x.Genre == movieGenre);
    }

    return View(movies);
}

Il parametro "All" fornisce un'etichetta di opzione. Se si controlla tale scelta nel browser, si noterà che l'attributo "value" è vuoto. Poiché il controller filtra if solo la stringa non null è o vuota, inviare un valore vuoto per movieGenre visualizzare tutti i generi.

È anche possibile impostare un'opzione da selezionare per impostazione predefinita. Se si vuole "Comedy" come opzione predefinita, si modifica il codice nel controller come segue:

ViewBag.movieGenre = new SelectList(GenreLst, "Comedy");

Eseguire l'applicazione e passare a /Movies/Index. Provare una ricerca per genere, per nome del film e per entrambi i criteri.

Screenshot che mostra la pagina Indice. Viene selezionato un tipo di genere.

In questa sezione è stato creato un metodo di azione di ricerca e una visualizzazione che consente agli utenti di cercare in base al titolo e al genere del film. Nella sezione successiva si esaminerà come aggiungere una proprietà al Movie modello e come aggiungere un inizializzatore che creerà automaticamente un database di test.