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.
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.
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.
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.
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>";
}
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))
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
.
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 ViewBag
oggetto , 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.
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.