Ajouter une fonction de recherche aux pages Razor dans ASP.NET CoreAdd search to ASP.NET Core Razor Pages

De Rick AndersonBy Rick Anderson

Dans les sections suivantes, la recherche de films par genre ou par nom est ajoutée.In the following sections, searching movies by genre or name is added.

Ajoutez les propriétés en surbrillance suivantes à Pages/Movies/Index.cshtml.cs :Add the following highlighted properties to 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; }
    [BindProperty(SupportsGet = true)]
    public string SearchString { get; set; }
    // Requires using Microsoft.AspNetCore.Mvc.Rendering;
    public SelectList Genres { get; set; }
    [BindProperty(SupportsGet = true)]
    public string MovieGenre { get; set; }
  • SearchString : contient le texte que les utilisateurs entrent dans la zone de texte de recherche.SearchString: contains the text users enter in the search text box. SearchString a l’attribut [BindProperty] .SearchString has the [BindProperty] attribute. [BindProperty] lie les valeurs de formulaire et les chaînes de requête avec le même nom que la propriété.[BindProperty] binds form values and query strings with the same name as the property. (SupportsGet = true) est obligatoire pour la liaison sur les requêtes GET.(SupportsGet = true) is required for binding on GET requests.
  • Genres : contient la liste des genres.Genres: contains the list of genres. Genres permet à l’utilisateur de sélectionner un genre dans la liste.Genres allows the user to select a genre from the list. SelectList nécessite using Microsoft.AspNetCore.Mvc.Rendering;SelectList requires using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre : contient le genre spécifique sélectionné par l’utilisateur (par exemple, « Western »).MovieGenre: contains the specific genre the user selects (for example, "Western").
  • Genres et MovieGenre sont utilisés plus loin dans ce tutoriel.Genres and MovieGenre are used later in this tutorial.

Avertissement

Pour des raisons de sécurité, vous devez choisir de lier les données de requête GET aux propriétés du modèle de page.For security reasons, you must opt in to binding GET request data to page model properties. Vérifiez l’entrée utilisateur avant de la mapper à des propriétés.Verify user input before mapping it to properties. L’utilisation de la liaison de GET est utile lors de l’adressage de scénarios qui reposent sur une chaîne de requête ou des valeurs de route.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

Pour lier une propriété à des demandes GET, affectez à la propriété SupportsGet de l’attribut [BindProperty] la valeur true:To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true:

[BindProperty(SupportsGet = true)]

Pour plus d’informations, consultez ASP.net Core de la communauté réunions : lier sur obtenir une discussion (YouTube).For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Mettez à jour la méthode OnGetAsync de la page Index avec le code suivant :Update the Index page's OnGetAsync method with the following code:

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 première ligne de la méthode OnGetAsync crée une requête LINQ pour sélectionner les films :The first line of the OnGetAsync method creates a LINQ query to select the movies:

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

La requête est seulement définie à ce stade ; elle n’a pas été exécutée sur la base de données.The query is only defined at this point, it has not been run against the database.

Si la propriété SearchString n’est pas nulle ou vide, la requête sur les films est modifiée de façon à filtrer sur la chaîne de recherche :If the SearchString property is not null or empty, the movies query is modified to filter on the search string:

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

Le code s => s.Title.Contains() est une expression lambda.The s => s.Title.Contains() code is a Lambda Expression. Les expressions lambda sont utilisées dans les requêtes LINQ basées sur une méthode comme arguments pour les méthodes d’opérateur de requête standard, telles que la méthode Where ou Contains (utilisée dans le code précédent).Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as the Where method or Contains (used in the preceding code). Les requêtes LINQ ne sont pas exécutées quand elles sont définies ou quand elles sont modifiées en appelant une méthode (comme Where, Contains ou OrderBy).LINQ queries are not executed when they're defined or when they're modified by calling a method (such as Where, Contains or OrderBy). Au lieu de cela, l’exécution de la requête est différée.Rather, query execution is deferred. Cela signifie que l’évaluation d’une expression est retardée jusqu’à ce que sa valeur réalisée fasse l’objet d’une itération réelle ou que la méthode ToListAsync soit appelée.That means the evaluation of an expression is delayed until its realized value is iterated over or the ToListAsync method is called. Pour plus d’informations, consultez Exécution de requête.See Query Execution for more information.

Notes

La méthode Contains est exécutée sur la base de données, et non pas dans le code C#.The Contains method is run on the database, not in the C# code. Le respect de la casse pour la requête dépend de la base de données et du classement.The case sensitivity on the query depends on the database and the collation. Sur SQL Server, Contains est mappée à SQL LIKE, qui ne respecte pas la casse.On SQL Server, Contains maps to SQL LIKE, which is case insensitive. Dans SQLite, avec le classement par défaut, elle respecte la casse.In SQLite, with the default collation, it's case sensitive.

Accédez à la page Movies, puis ajoutez une chaîne de requête telle que ?searchString=Ghost à l’URL (par exemple, https://localhost:5001/Movies?searchString=Ghost).Navigate to the Movies page and append a query string such as ?searchString=Ghost to the URL (for example, https://localhost:5001/Movies?searchString=Ghost). Les films filtrés sont affichés.The filtered movies are displayed.

Vue Index

Si le modèle de routing suivant est ajouté à la page d’index, la chaîne de recherche peut être passée comme un segment d’URL (par exemple, https://localhost:5001/Movies/Ghost).If the following route template is added to the Index page, the search string can be passed as a URL segment (for example, https://localhost:5001/Movies/Ghost).

@page "{searchString?}"

La contrainte d’itinéraire précédente permet de rechercher le titre comme données d’itinéraire (un segment d’URL) et non comme valeur de chaîne de requête.The preceding route constraint allows searching the title as route data (a URL segment) instead of as a query string value. Le ? dans "{searchString?}" signifie qu’il s’agit d’un paramètre d’itinéraire facultatif.The ? in "{searchString?}" means this is an optional route parameter.

Vue Index avec le mot « ghost » ajouté à l’URL, et une liste des films retournés avec deux films, Ghostbusters et Ghostbusters 2

Le runtime ASP.NET Core utilise la liaison de modèle pour définir la valeur de la propriété SearchString à partir de la chaîne de requête (?searchString=Ghost) ou des données de la route (https://localhost:5001/Movies/Ghost).The ASP.NET Core runtime uses model binding to set the value of the SearchString property from the query string (?searchString=Ghost) or route data (https://localhost:5001/Movies/Ghost). La liaison de modèle ne respecte pas la casse.Model binding is not case sensitive.

Cependant, vous ne pouvez pas attendre des utilisateurs qu’ils modifient l’URL pour rechercher un film.However, you can't expect users to modify the URL to search for a movie. Dans cette étape, une interface utilisateur est ajoutée pour filtrer les films.In this step, UI is added to filter movies. Si vous avez ajouté la contrainte d’itinéraire "{searchString?}", supprimez-la.If you added the route constraint "{searchString?}", remove it.

Ouvrez le fichier Pages/Movies/Index.cshtml, puis ajoutez la balise <form> mise en surbrillance dans le code suivant :Open the Pages/Movies/Index.cshtml file, and add the <form> markup highlighted in the following code:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

<h1>Index</h1>

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

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

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

La balise HTML <form> utilise les Tag Helpers suivants :The HTML <form> tag uses the following Tag Helpers:

Enregistrez les modifications apportées, puis testez le filtre.Save the changes and test the filter.

Vue Index avec le mot « ghost » tapé dans la zone de texte du filtre Title

Rechercher par genreSearch by genre

Mettez à jour la méthode OnGetAsync avec le code suivant :Update the OnGetAsync method with the following code:

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

Le code suivant est une requête LINQ qui récupère tous les genres dans la base de données.The following code is a LINQ query that retrieves all the genres from the database.

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

La liste SelectList de genres est créée en projetant des différents genres.The SelectList of genres is created by projecting the distinct genres.

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

Ajouter une recherche par genre à la page Razor PagesAdd search by genre to the Razor Page

Mettez à jour Index.cshtml comme suit :Update Index.cshtml as follows:

@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>
        Title: <input type="text" asp-for="SearchString" />
        <input type="submit" value="Filter" />
    </p>
</form>

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

Testez l’application en effectuant une recherche par genre, par titre de film et selon ces deux critères.Test the app by searching by genre, by movie title, and by both.

Ressources supplémentairesAdditional resources

Dans les sections suivantes, la recherche de films par genre ou par nom est ajoutée.In the following sections, searching movies by genre or name is added.

Ajoutez les propriétés en surbrillance suivantes à Pages/Movies/Index.cshtml.cs :Add the following highlighted properties to Pages/Movies/Index.cshtml.cs:

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

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

    public IList<Movie> Movie { get; set; }
    [BindProperty(SupportsGet = true)]
    public string SearchString { get; set; }
    // Requires using Microsoft.AspNetCore.Mvc.Rendering;
    public SelectList Genres { get; set; }
    [BindProperty(SupportsGet = true)]
    public string MovieGenre { get; set; }
  • SearchString : contient le texte que les utilisateurs entrent dans la zone de texte de recherche.SearchString: contains the text users enter in the search text box. SearchString a l’attribut [BindProperty] .SearchString has the [BindProperty] attribute. [BindProperty] lie les valeurs de formulaire et les chaînes de requête avec le même nom que la propriété.[BindProperty] binds form values and query strings with the same name as the property. (SupportsGet = true) est obligatoire pour la liaison sur les requêtes GET.(SupportsGet = true) is required for binding on GET requests.
  • Genres : contient la liste des genres.Genres: contains the list of genres. Genres permet à l’utilisateur de sélectionner un genre dans la liste.Genres allows the user to select a genre from the list. SelectList nécessite using Microsoft.AspNetCore.Mvc.Rendering;SelectList requires using Microsoft.AspNetCore.Mvc.Rendering;
  • MovieGenre : contient le genre spécifique sélectionné par l’utilisateur (par exemple, « Western »).MovieGenre: contains the specific genre the user selects (for example, "Western").
  • Genres et MovieGenre sont utilisés plus loin dans ce tutoriel.Genres and MovieGenre are used later in this tutorial.

Avertissement

Pour des raisons de sécurité, vous devez choisir de lier les données de requête GET aux propriétés du modèle de page.For security reasons, you must opt in to binding GET request data to page model properties. Vérifiez l’entrée utilisateur avant de la mapper à des propriétés.Verify user input before mapping it to properties. L’utilisation de la liaison de GET est utile lors de l’adressage de scénarios qui reposent sur une chaîne de requête ou des valeurs de route.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

Pour lier une propriété à des demandes GET, affectez à la propriété SupportsGet de l’attribut [BindProperty] la valeur true:To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true:

[BindProperty(SupportsGet = true)]

Pour plus d’informations, consultez ASP.net Core de la communauté réunions : lier sur obtenir une discussion (YouTube).For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Mettez à jour la méthode OnGetAsync de la page Index avec le code suivant :Update the Index page's OnGetAsync method with the following code:

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 première ligne de la méthode OnGetAsync crée une requête LINQ pour sélectionner les films :The first line of the OnGetAsync method creates a LINQ query to select the movies:

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

La requête est seulement définie à ce stade ; elle n’a pas été exécutée sur la base de données.The query is only defined at this point, it has not been run against the database.

Si la propriété SearchString n’est pas nulle ou vide, la requête sur les films est modifiée de façon à filtrer sur la chaîne de recherche :If the SearchString property is not null or empty, the movies query is modified to filter on the search string:

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

Le code s => s.Title.Contains() est une expression lambda.The s => s.Title.Contains() code is a Lambda Expression. Les expressions lambda sont utilisées dans les requêtes LINQ basées sur une méthode comme arguments pour les méthodes d’opérateur de requête standard, telles que la méthode Where ou Contains (utilisée dans le code précédent).Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as the Where method or Contains (used in the preceding code). Les requêtes LINQ ne sont pas exécutées quand elles sont définies ou quand elles sont modifiées en appelant une méthode (comme Where, Contains ou OrderBy).LINQ queries are not executed when they're defined or when they're modified by calling a method (such as Where, Contains or OrderBy). Au lieu de cela, l’exécution de la requête est différée.Rather, query execution is deferred. Cela signifie que l’évaluation d’une expression est retardée jusqu’à ce que sa valeur réalisée fasse l’objet d’une itération réelle ou que la méthode ToListAsync soit appelée.That means the evaluation of an expression is delayed until its realized value is iterated over or the ToListAsync method is called. Pour plus d’informations, consultez Exécution de requête.See Query Execution for more information.

Remarque : La méthode Contains est exécutée sur la base de données, et non pas dans le code C#.Note: The Contains method is run on the database, not in the C# code. Le respect de la casse pour la requête dépend de la base de données et du classement.The case sensitivity on the query depends on the database and the collation. Sur SQL Server, Contains est mappée à SQL LIKE, qui ne respecte pas la casse.On SQL Server, Contains maps to SQL LIKE, which is case insensitive. Dans SQLite, avec le classement par défaut, elle respecte la casse.In SQLite, with the default collation, it's case sensitive.

Accédez à la page Movies, puis ajoutez une chaîne de requête telle que ?searchString=Ghost à l’URL (par exemple, https://localhost:5001/Movies?searchString=Ghost).Navigate to the Movies page and append a query string such as ?searchString=Ghost to the URL (for example, https://localhost:5001/Movies?searchString=Ghost). Les films filtrés sont affichés.The filtered movies are displayed.

Vue Index

Si le modèle de routing suivant est ajouté à la page d’index, la chaîne de recherche peut être passée comme un segment d’URL (par exemple, https://localhost:5001/Movies/Ghost).If the following route template is added to the Index page, the search string can be passed as a URL segment (for example, https://localhost:5001/Movies/Ghost).

@page "{searchString?}"

La contrainte d’itinéraire précédente permet de rechercher le titre comme données d’itinéraire (un segment d’URL) et non comme valeur de chaîne de requête.The preceding route constraint allows searching the title as route data (a URL segment) instead of as a query string value. Le ? dans "{searchString?}" signifie qu’il s’agit d’un paramètre d’itinéraire facultatif.The ? in "{searchString?}" means this is an optional route parameter.

Vue Index avec le mot « ghost » ajouté à l’URL, et une liste des films retournés avec deux films, Ghostbusters et Ghostbusters 2

Le runtime ASP.NET Core utilise la liaison de modèle pour définir la valeur de la propriété SearchString à partir de la chaîne de requête (?searchString=Ghost) ou des données de la route (https://localhost:5001/Movies/Ghost).The ASP.NET Core runtime uses model binding to set the value of the SearchString property from the query string (?searchString=Ghost) or route data (https://localhost:5001/Movies/Ghost). La liaison de modèle ne respecte pas la casse.Model binding is not case sensitive.

Cependant, vous ne pouvez pas attendre des utilisateurs qu’ils modifient l’URL pour rechercher un film.However, you can't expect users to modify the URL to search for a movie. Dans cette étape, une interface utilisateur est ajoutée pour filtrer les films.In this step, UI is added to filter movies. Si vous avez ajouté la contrainte d’itinéraire "{searchString?}", supprimez-la.If you added the route constraint "{searchString?}", remove it.

Ouvrez le fichier Pages/Movies/Index.cshtml, puis ajoutez la balise <form> mise en surbrillance dans le code suivant :Open the Pages/Movies/Index.cshtml file, and add the <form> markup highlighted in the following code:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

<h1>Index</h1>

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

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

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

La balise HTML <form> utilise les Tag Helpers suivants :The HTML <form> tag uses the following Tag Helpers:

Enregistrez les modifications apportées, puis testez le filtre.Save the changes and test the filter.

Vue Index avec le mot « ghost » tapé dans la zone de texte du filtre Title

Rechercher par genreSearch by genre

Mettez à jour la méthode OnGetAsync avec le code suivant :Update the OnGetAsync method with the following code:

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

Le code suivant est une requête LINQ qui récupère tous les genres dans la base de données.The following code is a LINQ query that retrieves all the genres from the database.

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

La liste SelectList de genres est créée en projetant des différents genres.The SelectList of genres is created by projecting the distinct genres.

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

Ajouter une recherche par genre à la page Razor PagesAdd search by genre to the Razor Page

Mettez à jour Index.cshtml comme suit :Update Index.cshtml as follows:

@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>
        Title: <input type="text" asp-for="SearchString" />
        <input type="submit" value="Filter" />
    </p>
</form>

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

Testez l’application en effectuant une recherche par genre, par titre de film et selon ces deux critères.Test the app by searching by genre, by movie title, and by both. Le code précédent utilise le tag Helper Select et option tag Helper.The preceding code uses the Select Tag Helper and Option Tag Helper.

Ressources supplémentairesAdditional resources