Parte 6, aggiungere la ricerca a ASP.NET Pagine principali Razor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Di Rick Anderson

Nelle sezioni seguenti viene aggiunta la funzionalità di ricerca di film in base al genere oppure al nome.

Aggiungere il codice evidenziato seguente a Pages/Movies/Index.cshtml.cs:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

    public IList<Movie> Movie { get;set; }  = default!;

    [BindProperty(SupportsGet = true)]
    public string? SearchString { get; set; }

    public SelectList? Genres { get; set; }

    [BindProperty(SupportsGet = true)]
    public string? MovieGenre { get; set; }

Nel codice precedente:

  • SearchString: contiene il testo immesso dagli utenti nella casella di testo di ricerca. SearchString ha l'attributo [BindProperty] . [BindProperty] associa i valori modulo e le stringhe di query al nome della proprietà. [BindProperty(SupportsGet = true)] è obbligatorio per l'associazione nelle richieste HTTP GET.
  • Genres: contiene l'elenco dei generi. Genres consente all'utente di selezionare un genere dall'elenco. SelectList richiede using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre: contiene il genere specifico selezionato dall'utente. Ad esempio, "Western".
  • Genres e MovieGenre sono utilizzati più avanti in questa esercitazione.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà. Acconsentire esplicitamente all'associazione GET è utile in scenari basati su valori route o stringa di query.

Per associare una proprietà nelle richieste GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Aggiornare il Movies/Index metodo della OnGetAsync pagina con il codice seguente:

public async Task OnGetAsync()
{
    var movies = from m in _context.Movie
                 select m;
    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    Movie = await movies.ToListAsync();
}

La prima riga del metodo OnGetAsync crea una query LINQ per selezionare i film:

var movies = from m in _context.Movie
             select m;

La query viene solo definita in questo punto, ma non viene eseguita nel database.

Se la SearchString proprietà non null è o vuota, la query movies viene modificata per filtrare la stringa di ricerca:

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

Il codice s => s.Title.Contains() è 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 o Contains. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo, ad esempio Where, Containso OrderBy. L'esecuzione della query viene invece posticipata. La valutazione di un'espressione viene ritardata fino a quando non viene eseguito l'iterazione del relativo valore realizzato o viene chiamato il ToListAsync metodo . Per altre informazioni, vedere Esecuzione di query.

Nota

Il Contains metodo viene eseguito nel database, non nel codice C#. La distinzione tra maiuscole/minuscole nella query dipende dal database e dalle regole di confronto. In SQL Server Contains esegue il mapping a SQL LIKE che fa distinzione tra maiuscole e minuscole. SQLite con le regole di confronto predefinite è una combinazione di distinzione tra maiuscole e minuscole e di distinzione tra maiuscole e minuscole, a seconda della query. Per informazioni sull'esecuzione di query SQLite senza distinzione tra maiuscole e minuscole, vedere quanto segue:

Passare alla pagina Film e aggiungere una stringa di query, ?searchString=Ghost ad esempio all'URL. Ad esempio: https://localhost:5001/Movies?searchString=Ghost. Vengono visualizzati i film filtrati.

Vista Index

Se il modello di route seguente viene aggiunto alla pagina Indice, la stringa di ricerca può essere passata come segmento di URL. Ad esempio: https://localhost:5001/Movies/Ghost.

@page "{searchString?}"

Il vincolo di route precedente consente la ricerca del titolo come dati della route (un segmento URL), anziché come valore della stringa di query. Il carattere ? in "{searchString?}" indica che questo parametro di route è facoltativo.

Vista Index con la parola ghost aggiunta all'URL e un elenco restituito di due film: Ghostbusters e Ghostbusters 2

Il runtime di ASP.NET Core usa l'associazione di modelli per impostare il valore della proprietà SearchString dalla stringa di query (?searchString=Ghost) o dai dati della route (https://localhost:5001/Movies/Ghost). L'associazione di modelli non fa distinzione tra maiuscole e minuscole.

Tuttavia, non è previsto che gli utenti modifichino l'URL per cercare un filmato. In questo passaggio viene aggiunta l'interfaccia utente per filtrare i film. Rimuovere il vincolo di route "{searchString?}", se è stato aggiunto.

Aprire il Pages/Movies/Index.cshtml file e aggiungere il markup evidenziato nel codice seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

<table class="table">
    <thead>

Il tag HTML <form> usa gli helper tag seguenti:

Salvare le modifiche e testare il filtro.

Vista Index con la parola ghost digitata nella casella di testo del filtro del titolo

Ricerca in base al genere

Aggiornare il Movies/Index.cshtml.cs metodo page OnGetAsync con il codice seguente:

public async Task OnGetAsync()
{
    // <snippet_search_linqQuery>
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;
    // </snippet_search_linqQuery>

    var movies = from m in _context.Movie
                 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);
    }

    // <snippet_search_selectList>
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    // </snippet_search_selectList>
    Movie = await movies.ToListAsync();
}

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

IQueryable<string> genreQuery = from m in _context.Movie
                                orderby m.Genre
                                select m.Genre;

Il SelectList di genere viene creato proiettando i generi distinti:

Genres = new SelectList(await genreQuery.Distinct().ToListAsync());

Aggiungere la ricerca per genere alla Razor pagina

Aggiornare l'elemento Index.cshtml <form> come evidenziato nel markup seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <select asp-for="MovieGenre" asp-items="Model.Genres">
            <option value="">All</option>
        </select>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

Eseguire il test dell'app effettuando una ricerca per genere, titolo del film ed entrambi:

Visualizzazione indice completata con i filtri di ricerca del selettore Genere e Casella di testo Titolo

Passaggi successivi

Nelle sezioni seguenti viene aggiunta la funzionalità di ricerca di film in base al genere oppure al nome.

Aggiungere il codice evidenziato seguente a Pages/Movies/Index.cshtml.cs:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

    public IList<Movie> Movie { get;set; }  = default!;

    [BindProperty(SupportsGet = true)]
    public string? SearchString { get; set; }

    public SelectList? Genres { get; set; }

    [BindProperty(SupportsGet = true)]
    public string? MovieGenre { get; set; }

Nel codice precedente:

  • SearchString: contiene il testo immesso dagli utenti nella casella di testo di ricerca. SearchString ha l'attributo [BindProperty] . [BindProperty] associa i valori modulo e le stringhe di query al nome della proprietà. [BindProperty(SupportsGet = true)] è obbligatorio per l'associazione nelle richieste HTTP GET.
  • Genres: contiene l'elenco dei generi. Genres consente all'utente di selezionare un genere dall'elenco. SelectList richiede using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre: contiene il genere specifico selezionato dall'utente. Ad esempio, "Western".
  • Genres e MovieGenre sono utilizzati più avanti in questa esercitazione.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà. Acconsentire esplicitamente all'associazione GET è utile in scenari basati su valori route o stringa di query.

Per associare una proprietà nelle richieste GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    var movies = from m in _context.Movie
                 select m;
    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    Movie = await movies.ToListAsync();
}

La prima riga del metodo OnGetAsync crea una query LINQ per selezionare i film:

// using System.Linq;
var movies = from m in _context.Movie
             select m;

La query viene solo definita in questo punto, ma non viene eseguita nel database.

Se la SearchString proprietà non null è o vuota, la query movies viene modificata per filtrare la stringa di ricerca:

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

Il codice s => s.Title.Contains() è 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 o Contains. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo, ad esempio Where, Containso OrderBy. L'esecuzione della query viene invece posticipata. La valutazione di un'espressione viene ritardata fino a quando non viene eseguito l'iterazione del relativo valore realizzato o viene chiamato il ToListAsync metodo . Per altre informazioni, vedere Esecuzione di query.

Nota

Il Contains metodo viene eseguito nel database, non nel codice C#. La distinzione tra maiuscole/minuscole nella query dipende dal database e dalle regole di confronto. In SQL Server Contains esegue il mapping a SQL LIKE che fa distinzione tra maiuscole e minuscole. SQLite con le regole di confronto predefinite è una combinazione di distinzione tra maiuscole e minuscole e di distinzione tra maiuscole e minuscole, a seconda della query. Per informazioni sull'esecuzione di query SQLite senza distinzione tra maiuscole e minuscole, vedere quanto segue:

Passare alla pagina Film e aggiungere una stringa di query, ?searchString=Ghost ad esempio all'URL. Ad esempio: https://localhost:5001/Movies?searchString=Ghost. Vengono visualizzati i film filtrati.

Vista Index

Se il modello di route seguente viene aggiunto alla pagina Indice, la stringa di ricerca può essere passata come segmento di URL. Ad esempio: https://localhost:5001/Movies/Ghost.

@page "{searchString?}"

Il vincolo di route precedente consente la ricerca del titolo come dati della route (un segmento URL), anziché come valore della stringa di query. Il carattere ? in "{searchString?}" indica che questo parametro di route è facoltativo.

Vista Index con la parola ghost aggiunta all'URL e un elenco restituito di due film: Ghostbusters e Ghostbusters 2

Il runtime di ASP.NET Core usa l'associazione di modelli per impostare il valore della proprietà SearchString dalla stringa di query (?searchString=Ghost) o dai dati della route (https://localhost:5001/Movies/Ghost). L'associazione di modelli non fa distinzione tra maiuscole e minuscole.

Tuttavia, non è previsto che gli utenti modifichino l'URL per cercare un filmato. In questo passaggio viene aggiunta l'interfaccia utente per filtrare i film. Rimuovere il vincolo di route "{searchString?}", se è stato aggiunto.

Aprire il Pages/Movies/Index.cshtml file e aggiungere il markup evidenziato nel codice seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

<table class="table">
    @*Markup removed for brevity.*@

Il tag HTML <form> usa gli helper tag seguenti:

Salvare le modifiche e testare il filtro.

Vista Index con la parola ghost digitata nella casella di testo del filtro del titolo

Ricerca in base al genere

Aggiornare il Movies/Index.cshtml.cs metodo page OnGetAsync con il codice seguente:

public async Task OnGetAsync()
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 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);
    }
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    Movie = await movies.ToListAsync();
}

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

// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
                                orderby m.Genre
                                select m.Genre;

L'elenco SelectList di generi viene creato selezionando generi distinti.

Genres = new SelectList(await genreQuery.Distinct().ToListAsync());

Aggiungere la ricerca per genere alla Razor pagina

Aggiornare l'elemento Index.cshtml <form> come evidenziato nel markup seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <select asp-for="MovieGenre" asp-items="Model.Genres">
            <option value="">All</option>
        </select>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

Eseguire il test dell'app effettuando una ricerca per genere, titolo del film e usando entrambi i filtri.

Passaggi successivi

Nelle sezioni seguenti viene aggiunta la funzionalità di ricerca di film in base al genere oppure al nome.

Aggiungere il codice evidenziato seguente a Pages/Movies/Index.cshtml.cs:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

    public IList<Movie> Movie { get;set; }  = default!;

    [BindProperty(SupportsGet = true)]
    public string? SearchString { get; set; }

    public SelectList? Genres { get; set; }

    [BindProperty(SupportsGet = true)]
    public string? MovieGenre { get; set; }

Nel codice precedente:

  • SearchString: contiene il testo immesso dagli utenti nella casella di testo di ricerca. SearchString ha l'attributo [BindProperty] . [BindProperty] associa i valori modulo e le stringhe di query al nome della proprietà. [BindProperty(SupportsGet = true)] è obbligatorio per l'associazione nelle richieste HTTP GET.
  • Genres: contiene l'elenco dei generi. Genres consente all'utente di selezionare un genere dall'elenco. SelectList richiede using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre: contiene il genere specifico selezionato dall'utente. Ad esempio, "Western".
  • Genres e MovieGenre sono utilizzati più avanti in questa esercitazione.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà. Acconsentire esplicitamente all'associazione GET è utile in scenari basati su valori route o stringa di query.

Per associare una proprietà nelle richieste GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    var movies = from m in _context.Movie
                 select m;
    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    Movie = await movies.ToListAsync();
}

La prima riga del metodo OnGetAsync crea una query LINQ per selezionare i film:

// using System.Linq;
var movies = from m in _context.Movie
             select m;

La query viene solo definita in questo punto, ma non viene eseguita nel database.

Se la SearchString proprietà non null è o vuota, la query movies viene modificata per filtrare la stringa di ricerca:

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

Il codice s => s.Title.Contains() è 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 o Contains. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo, ad esempio Where, Containso OrderBy. L'esecuzione della query viene invece posticipata. La valutazione di un'espressione viene ritardata fino a quando non viene eseguito l'iterazione del relativo valore realizzato o viene chiamato il ToListAsync metodo . Per altre informazioni, vedere Esecuzione di query.

Nota

Il Contains metodo viene eseguito nel database, non nel codice C#. La distinzione tra maiuscole/minuscole nella query dipende dal database e dalle regole di confronto. In SQL Server Contains esegue il mapping a SQL LIKE che fa distinzione tra maiuscole e minuscole. SQLite con le regole di confronto predefinite è una combinazione di distinzione tra maiuscole e minuscole e di distinzione tra maiuscole e minuscole, a seconda della query. Per informazioni sull'esecuzione di query SQLite senza distinzione tra maiuscole e minuscole, vedere quanto segue:

Passare alla pagina Film e aggiungere una stringa di query, ?searchString=Ghost ad esempio all'URL. Ad esempio: https://localhost:5001/Movies?searchString=Ghost. Vengono visualizzati i film filtrati.

Vista Index

Se il modello di route seguente viene aggiunto alla pagina Indice, la stringa di ricerca può essere passata come segmento di URL. Ad esempio: https://localhost:5001/Movies/Ghost.

@page "{searchString?}"

Il vincolo di route precedente consente la ricerca del titolo come dati della route (un segmento URL), anziché come valore della stringa di query. Il carattere ? in "{searchString?}" indica che questo parametro di route è facoltativo.

Vista Index con la parola ghost aggiunta all'URL e un elenco restituito di due film: Ghostbusters e Ghostbusters 2

Il runtime di ASP.NET Core usa l'associazione di modelli per impostare il valore della proprietà SearchString dalla stringa di query (?searchString=Ghost) o dai dati della route (https://localhost:5001/Movies/Ghost). L'associazione di modelli non fa distinzione tra maiuscole e minuscole.

Tuttavia, non è previsto che gli utenti modifichino l'URL per cercare un filmato. In questo passaggio viene aggiunta l'interfaccia utente per filtrare i film. Rimuovere il vincolo di route "{searchString?}", se è stato aggiunto.

Aprire il Pages/Movies/Index.cshtml file e aggiungere il markup evidenziato nel codice seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

<table class="table">
    @*Markup removed for brevity.*@

Il tag HTML <form> usa gli helper tag seguenti:

Salvare le modifiche e testare il filtro.

Vista Index con la parola ghost digitata nella casella di testo del filtro del titolo

Ricerca in base al genere

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 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);
    }
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    Movie = await movies.ToListAsync();
}

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

// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
                                orderby m.Genre
                                select m.Genre;

L'elenco SelectList di generi viene creato selezionando generi distinti.

Genres = new SelectList(await genreQuery.Distinct().ToListAsync());

Aggiungere la ricerca per genere alla Razor pagina

Aggiornare l'elemento Index.cshtml <form> come evidenziato nel markup seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <select asp-for="MovieGenre" asp-items="Model.Genres">
            <option value="">All</option>
        </select>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

Eseguire il test dell'app effettuando una ricerca per genere, titolo del film e usando entrambi i filtri.

Passaggi successivi

Nelle sezioni seguenti viene aggiunta la funzionalità di ricerca di film in base al genere oppure al nome.

Aggiungere il codice evidenziato seguente a Pages/Movies/Index.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get;set; } = default!;
        [BindProperty(SupportsGet = true)]
        public string ? SearchString { get; set; }
        public SelectList ? Genres { get; set; }
        [BindProperty(SupportsGet = true)]
        public string ? MovieGenre { get; set; }

Nel codice precedente:

  • SearchString: contiene il testo immesso dagli utenti nella casella di testo di ricerca. SearchString ha l'attributo [BindProperty] . [BindProperty] associa i valori modulo e le stringhe di query al nome della proprietà. [BindProperty(SupportsGet = true)] è obbligatorio per l'associazione nelle richieste HTTP GET.
  • Genres: contiene l'elenco dei generi. Genres consente all'utente di selezionare un genere dall'elenco. SelectList richiede using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre: contiene il genere specifico selezionato dall'utente. Ad esempio, "Western".
  • Genres e MovieGenre sono utilizzati più avanti in questa esercitazione.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà. Acconsentire esplicitamente all'associazione GET è utile in scenari basati su valori route o stringa di query.

Per associare una proprietà nelle richieste GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    var movies = from m in _context.Movie
                 select m;
    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    Movie = await movies.ToListAsync();
}

La prima riga del metodo OnGetAsync crea una query LINQ per selezionare i film:

// using System.Linq;
var movies = from m in _context.Movie
             select m;

La query viene solo definita in questo punto, ma non viene eseguita nel database.

Se la proprietà SearchString non è null o vuota, la query dei film viene modificata per filtrare gli elementi in base alla stringa di ricerca:

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

Il codice s => s.Title.Contains() è 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 o Contains. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo, ad esempio Where, Containso OrderBy. L'esecuzione della query viene invece posticipata. La valutazione di un'espressione viene ritardata fino a quando non viene eseguito l'iterazione del relativo valore realizzato o viene chiamato il ToListAsync metodo . Per altre informazioni, vedere Esecuzione di query.

Nota

Il Contains metodo viene eseguito nel database, non nel codice C#. La distinzione tra maiuscole/minuscole nella query dipende dal database e dalle regole di confronto. In SQL Server Contains esegue il mapping a SQL LIKE che fa distinzione tra maiuscole e minuscole. SQLite con le regole di confronto predefinite è una combinazione di distinzione tra maiuscole e minuscole e di distinzione tra maiuscole e minuscole, a seconda della query. Per informazioni sull'esecuzione di query SQLite senza distinzione tra maiuscole e minuscole, vedere quanto segue:

Passare alla pagina Film e aggiungere una stringa di query, ?searchString=Ghost ad esempio all'URL. Ad esempio: https://localhost:5001/Movies?searchString=Ghost. Vengono visualizzati i film filtrati.

Vista Index

Se il modello di route seguente viene aggiunto alla pagina Indice, la stringa di ricerca può essere passata come segmento di URL. Ad esempio: https://localhost:5001/Movies/Ghost.

@page "{searchString?}"

Il vincolo di route precedente consente la ricerca del titolo come dati della route (un segmento URL), anziché come valore della stringa di query. Il carattere ? in "{searchString?}" indica che questo parametro di route è facoltativo.

Vista Index con la parola ghost aggiunta all'URL e un elenco restituito di due film: Ghostbusters e Ghostbusters 2

Il runtime di ASP.NET Core usa l'associazione di modelli per impostare il valore della proprietà SearchString dalla stringa di query (?searchString=Ghost) o dai dati della route (https://localhost:5001/Movies/Ghost). L'associazione di modelli non fa distinzione tra maiuscole e minuscole.

Tuttavia, non è previsto che gli utenti modifichino l'URL per cercare un filmato. In questo passaggio viene aggiunta l'interfaccia utente per filtrare i film. Rimuovere il vincolo di route "{searchString?}", se è stato aggiunto.

Aprire il Pages/Movies/Index.cshtml file e aggiungere il markup evidenziato nel codice seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

<table class="table">
    @*Markup removed for brevity.*@

Il tag HTML <form> usa gli helper tag seguenti:

Salvare le modifiche e testare il filtro.

Vista Index con la parola ghost digitata nella casella di testo del filtro del titolo

Ricerca in base al genere

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 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);
    }
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    Movie = await movies.ToListAsync();
}

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

// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
                                orderby m.Genre
                                select m.Genre;

L'elenco SelectList di generi viene creato selezionando generi distinti.

Genres = new SelectList(await genreQuery.Distinct().ToListAsync());

Aggiungere la ricerca per genere alla Razor pagina

Aggiornare l'elemento Index.cshtml <form> come evidenziato nel markup seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <select asp-for="MovieGenre" asp-items="Model.Genres">
            <option value="">All</option>
        </select>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

Eseguire il test dell'app effettuando una ricerca per genere, titolo del film e usando entrambi i filtri.

Passaggi successivi

Nelle sezioni seguenti viene aggiunta la funzionalità di ricerca di film in base al genere oppure al nome.

Aggiungere le proprietà e l'istruzione using seguenti evidenziate a Pages/Movies/Index.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{

    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get; set; }
        [BindProperty(SupportsGet = true)]
        public string SearchString { get; set; }
        public SelectList Genres { get; set; }
        [BindProperty(SupportsGet = true)]
        public string MovieGenre { get; set; }

Nel codice precedente:

  • SearchString: contiene il testo immesso dagli utenti nella casella di testo di ricerca. SearchString ha l'attributo [BindProperty] . [BindProperty] associa i valori modulo e le stringhe di query al nome della proprietà. [BindProperty(SupportsGet = true)] è obbligatorio per l'associazione nelle richieste HTTP GET.
  • Genres: contiene l'elenco dei generi. Genres consente all'utente di selezionare un genere dall'elenco. SelectList richiede using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre: contiene il genere specifico selezionato dall'utente. Ad esempio, "Western".
  • Genres e MovieGenre sono utilizzati più avanti in questa esercitazione.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà. Acconsentire esplicitamente all'associazione GET è utile in scenari basati su valori route o stringa di query.

Per associare una proprietà nelle richieste GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    var movies = from m in _context.Movie
                 select m;
    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    Movie = await movies.ToListAsync();
}

La prima riga del metodo OnGetAsync crea una query LINQ per selezionare i film:

// using System.Linq;
var movies = from m in _context.Movie
             select m;

La query viene solo definita in questo punto, ma non viene eseguita nel database.

Se la proprietà SearchString non è null o vuota, la query dei film viene modificata per filtrare gli elementi in base alla stringa di ricerca:

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

Il codice s => s.Title.Contains() è 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 o Contains. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo, ad esempio Where, Containso OrderBy. L'esecuzione della query viene invece posticipata. La valutazione di un'espressione viene ritardata fino a quando non viene eseguito l'iterazione del relativo valore realizzato o viene chiamato il ToListAsync metodo . Per altre informazioni, vedere Esecuzione di query.

Nota

Il Contains metodo viene eseguito nel database, non nel codice C#. La distinzione tra maiuscole/minuscole nella query dipende dal database e dalle regole di confronto. In SQL Server Contains esegue il mapping a SQL LIKE che fa distinzione tra maiuscole e minuscole. SQLite con le regole di confronto predefinite è una combinazione di distinzione tra maiuscole e minuscole e di distinzione tra maiuscole e minuscole, a seconda della query. Per informazioni sull'esecuzione di query SQLite senza distinzione tra maiuscole e minuscole, vedere quanto segue:

Passare alla pagina Film e aggiungere una stringa di query, ?searchString=Ghost ad esempio all'URL. Ad esempio: https://localhost:5001/Movies?searchString=Ghost. Vengono visualizzati i film filtrati.

Vista Index

Se il modello di route seguente viene aggiunto alla pagina Indice, la stringa di ricerca può essere passata come segmento di URL. Ad esempio: https://localhost:5001/Movies/Ghost.

@page "{searchString?}"

Il vincolo di route precedente consente la ricerca del titolo come dati della route (un segmento URL), anziché come valore della stringa di query. Il carattere ? in "{searchString?}" indica che questo parametro di route è facoltativo.

Vista Index con la parola ghost aggiunta all'URL e un elenco restituito di due film: Ghostbusters e Ghostbusters 2

Il runtime di ASP.NET Core usa l'associazione di modelli per impostare il valore della proprietà SearchString dalla stringa di query (?searchString=Ghost) o dai dati della route (https://localhost:5001/Movies/Ghost). L'associazione di modelli non fa distinzione tra maiuscole e minuscole.

Tuttavia, non è previsto che gli utenti modifichino l'URL per cercare un filmato. In questo passaggio viene aggiunta l'interfaccia utente per filtrare i film. Rimuovere il vincolo di route "{searchString?}", se è stato aggiunto.

Aprire il Pages/Movies/Index.cshtml file e aggiungere il markup evidenziato nel codice seguente:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<form>
    <p>
        <label>Title: <input type="text" asp-for="SearchString" /></label>
        <input type="submit" value="Filter" />
    </p>
</form>

<table class="table">
    @*Markup removed for brevity.*@

Il tag HTML <form> usa gli helper tag seguenti:

Salvare le modifiche e testare il filtro.

Vista Index con la parola ghost digitata nella casella di testo del filtro del titolo

Ricerca in base al genere

Aggiornare il metodo OnGetAsync della pagina di indice con il codice seguente:

public async Task OnGetAsync()
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 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);
    }
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    Movie = await movies.ToListAsync();
}

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

// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
                                orderby m.Genre
                                select m.Genre;

L'elenco SelectList di generi viene creato selezionando generi distinti.

Genres = new SelectList(await genreQuery.Distinct().ToListAsync());

Aggiungere la ricerca per genere alla Razor pagina

  1. Aggiornare l'elemento Index.cshtml <form> come evidenziato nel markup seguente:

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
        @*Markup removed for brevity.*@
    
    
  2. Eseguire il test dell'app effettuando una ricerca per genere, titolo del film e usando entrambi i filtri.

Passaggi successivi