パート 6、ASP.NET Core Razor ページへの検索の追加
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
作成者: Rick Anderson
次のセクションでは、ジャンルまたは名前による映画検索が追加されます。
次の強調表示されたコードを 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; }
上のコードでは、次のようになります。
SearchString
: ユーザーが検索テキスト ボックスに入力したテキストが含まれる。SearchString
には、[BindProperty]
属性があります。[BindProperty]
により、プロパティと同じ名前に基づきフォーム値とクエリ文字列がバインドされます。 HTTP GET 要求でのバインドには[BindProperty(SupportsGet = true)]
が必要です。Genres
: ジャンル一覧が含まれる。Genres
により、ユーザーは一覧からジャンルを選択できます。SelectList
にはusing Microsoft.AspNetCore.Mvc.Rendering;
が必要です。MovieGenre
: ユーザーが選択する特定のジャンルが含まれる。 たとえば、"Western (西部劇)" です。Genres
とMovieGenre
は、このチュートリアルで後述します。
警告
セキュリティ上の理由から、ページ モデルのプロパティに対して GET
要求データのバインドをオプトインする必要があります。 プロパティにマップする前に、ユーザー入力を確認してください。 GET
バインドをオプトインするのは、クエリ文字列やルート値に依存するシナリオに対処する場合に便利です。
GET
要求のプロパティをバインドするには、[BindProperty]
属性の SupportsGet
プロパティを true
に設定します。
[BindProperty(SupportsGet = true)]
詳細については、「ASP.NET Core コミュニティ スタンドアップ: GET ディスカッション (YouTube) でのバインド」を参照してください。
Movies/Index
ページの OnGetAsync
メソッドを次のコードで更新します。
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();
}
OnGetAsync
メソッドの最初の行により、ムービーを選択する LINQ クエリが作成されます。
var movies = from m in _context.Movie
select m;
このクエリは、この時点では "定義されている" だけであり、データベースに対して実行されているわけでは "ありません"。
SearchString
プロパティが null
でも空でもない場合、検索文字列で絞り込むようにムービークエリが変更されます。
if (!string.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.Title.Contains(SearchString));
}
s => s.Title.Contains()
コードはラムダ式です。 ラムダは、メソッド ベースの LINQ クエリで、Where メソッドや Contains
など、標準クエリ演算子メソッドの引数として使用されます。 LINQ クエリは、Where
、Contains
、OrderBy
などのメソッドの呼び出しで定義または変更されたときには実行されません。 クエリ実行は先送りされます。 その具体値が繰り返されるか、ToListAsync
メソッドが呼び出されるまで、式の評価が延ばされます。 詳細については、「クエリ実行」を参照してください。
Note
Contains メソッドは C# コードではなく、データベースで実行されます。 クエリの大文字と小文字の区別は、データベースや照合順序に依存します。 SQL Server では、Contains
は大文字/小文字の区別がない SQL LIKE にマッピングされます。 既定の照合順序での SQLite は、クエリに応じて、大文字と小文字を区別する場合と区別 "しない" 場合が混在します。 大文字と小文字を区別しない SQLite クエリの作成については、次を参照してください。
ムービー ページに移動し、?searchString=Ghost
のようなクエリ文字列を URL に追加します。 たとえば、「 https://localhost:5001/Movies?searchString=Ghost
」のように入力します。 フィルターされたムービーが表示されます。
次のルート テンプレートが Index ページに追加される場合、検索文字列を URL セグメントとして渡すことができます。 たとえば、「 https://localhost:5001/Movies/Ghost
」のように入力します。
@page "{searchString?}"
先のルート制約では、クエリ文字列値の代わりに、ルート データ (URL セグメント) として題名を検索できます。 "{searchString?}"
の ?
は、これが任意のルート パラメーターであることを意味します。
ASP.NET Core ランタイムではモデル バインドを使用し、クエリ文字列 (?searchString=Ghost
) またはルート データ (https://localhost:5001/Movies/Ghost
) から SearchString
プロパティの値が設定されます。 モデル バインドでは、大文字と小文字は区別 "されません"。
ただし、URL を変更してムービーを検索することをユーザーに求めることはできません。 この手順では、ムービーを絞り込むための UI を追加します。 ルート制約 "{searchString?}"
を追加した場合、それを削除します。
Pages/Movies/Index.cshtml
ファイルを開き、次のコードで強調表示されているマークアップを追加します。
@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>
HTML <form>
タグでは、次のタグ ヘルパーが使用されます。
- フォーム タグ ヘルパー フォームが提出されると、フィルター文字列がクエリ文字列経由でページ/ムービー/索引ページに送信されます。
- 入力タグ ヘルパー
変更を保存し、フィルターをテストします。
ジャンルで検索する
Movies/Index.cshtml.cs
ページの OnGetAsync
メソッドを次のコードで更新します。
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();
}
次のコードは、データベースからすべてのジャンルを取得する LINQ クエリです。
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
一意のジャンルを投影することによってジャンルの SelectList
を作成します。
Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
ジャンル検索を Razor ページに追加する
Index.cshtml
の <form>
要素を、次のマークアップで強調されている部分のとおりに更新します。
@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>
ジャンルまたはムービーのタイトル、あるいはその両方で検索して、アプリをテストします。
次のステップ
次のセクションでは、ジャンルまたは名前による映画検索が追加されます。
次の強調表示されたコードを 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; }
上のコードでは、次のようになります。
SearchString
: ユーザーが検索テキスト ボックスに入力したテキストが含まれる。SearchString
には、[BindProperty]
属性があります。[BindProperty]
により、プロパティと同じ名前に基づきフォーム値とクエリ文字列がバインドされます。 HTTP GET 要求でのバインドには[BindProperty(SupportsGet = true)]
が必要です。Genres
: ジャンル一覧が含まれる。Genres
により、ユーザーは一覧からジャンルを選択できます。SelectList
にはusing Microsoft.AspNetCore.Mvc.Rendering;
が必要です。MovieGenre
: ユーザーが選択する特定のジャンルが含まれる。 たとえば、"Western (西部劇)" です。Genres
とMovieGenre
は、このチュートリアルで後述します。
警告
セキュリティ上の理由から、ページ モデルのプロパティに対して GET
要求データのバインドをオプトインする必要があります。 プロパティにマップする前に、ユーザー入力を確認してください。 GET
バインドをオプトインするのは、クエリ文字列やルート値に依存するシナリオに対処する場合に便利です。
GET
要求のプロパティをバインドするには、[BindProperty]
属性の SupportsGet
プロパティを true
に設定します。
[BindProperty(SupportsGet = true)]
詳細については、「ASP.NET Core コミュニティ スタンドアップ: GET ディスカッション (YouTube) でのバインド」を参照してください。
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
OnGetAsync
メソッドの最初の行により、ムービーを選択する LINQ クエリが作成されます。
// using System.Linq;
var movies = from m in _context.Movie
select m;
このクエリは、この時点では "定義されている" だけであり、データベースに対して実行されているわけでは "ありません"。
SearchString
プロパティが null
でも空でもない場合、検索文字列で絞り込むようにムービークエリが変更されます。
if (!string.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.Title.Contains(SearchString));
}
s => s.Title.Contains()
コードはラムダ式です。 ラムダは、メソッド ベースの LINQ クエリで、Where メソッドや Contains
など、標準クエリ演算子メソッドの引数として使用されます。 LINQ クエリは、Where
、Contains
、OrderBy
などのメソッドの呼び出しで定義または変更されたときには実行されません。 クエリ実行は先送りされます。 その具体値が繰り返されるか、ToListAsync
メソッドが呼び出されるまで、式の評価が延ばされます。 詳細については、「クエリ実行」を参照してください。
Note
Contains メソッドは C# コードではなく、データベースで実行されます。 クエリの大文字と小文字の区別は、データベースや照合順序に依存します。 SQL Server では、Contains
は大文字/小文字の区別がない SQL LIKE にマッピングされます。 既定の照合順序での SQLite は、クエリに応じて、大文字と小文字を区別する場合と区別 "しない" 場合が混在します。 大文字と小文字を区別しない SQLite クエリの作成については、次を参照してください。
ムービー ページに移動し、?searchString=Ghost
のようなクエリ文字列を URL に追加します。 たとえば、「 https://localhost:5001/Movies?searchString=Ghost
」のように入力します。 フィルターされたムービーが表示されます。
次のルート テンプレートが Index ページに追加される場合、検索文字列を URL セグメントとして渡すことができます。 たとえば、「 https://localhost:5001/Movies/Ghost
」のように入力します。
@page "{searchString?}"
先のルート制約では、クエリ文字列値の代わりに、ルート データ (URL セグメント) として題名を検索できます。 "{searchString?}"
の ?
は、これが任意のルート パラメーターであることを意味します。
ASP.NET Core ランタイムではモデル バインドを使用し、クエリ文字列 (?searchString=Ghost
) またはルート データ (https://localhost:5001/Movies/Ghost
) から SearchString
プロパティの値が設定されます。 モデル バインドでは、大文字と小文字は区別 "されません"。
ただし、URL を変更してムービーを検索することをユーザーに求めることはできません。 この手順では、ムービーを絞り込むための UI を追加します。 ルート制約 "{searchString?}"
を追加した場合、それを削除します。
Pages/Movies/Index.cshtml
ファイルを開き、次のコードで強調表示されているマークアップを追加します。
@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.*@
HTML <form>
タグでは、次のタグ ヘルパーが使用されます。
- フォーム タグ ヘルパー フォームが提出されると、フィルター文字列がクエリ文字列経由でページ/ムービー/索引ページに送信されます。
- 入力タグ ヘルパー
変更を保存し、フィルターをテストします。
ジャンルで検索する
Movies/Index.cshtml.cs
ページの OnGetAsync
メソッドを次のコードで更新します。
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();
}
次のコードは、データベースからすべてのジャンルを取得する LINQ クエリです。
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
ジャンルの SelectList
は、別個のジャンルを推定することで作成されます。
Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
ジャンル検索を Razor ページに追加する
Index.cshtml
の <form>
要素を、次のマークアップで強調されている部分のとおりに更新します。
@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>
ジャンルまたはムービーのタイトル、あるいはその両方で検索して、アプリをテストします。
次のステップ
次のセクションでは、ジャンルまたは名前による映画検索が追加されます。
次の強調表示されたコードを 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; }
上のコードでは、次のようになります。
SearchString
: ユーザーが検索テキスト ボックスに入力したテキストが含まれる。SearchString
には、[BindProperty]
属性があります。[BindProperty]
により、プロパティと同じ名前に基づきフォーム値とクエリ文字列がバインドされます。 HTTP GET 要求でのバインドには[BindProperty(SupportsGet = true)]
が必要です。Genres
: ジャンル一覧が含まれる。Genres
により、ユーザーは一覧からジャンルを選択できます。SelectList
にはusing Microsoft.AspNetCore.Mvc.Rendering;
が必要です。MovieGenre
: ユーザーが選択する特定のジャンルが含まれる。 たとえば、"Western (西部劇)" です。Genres
とMovieGenre
は、このチュートリアルで後述します。
警告
セキュリティ上の理由から、ページ モデルのプロパティに対して GET
要求データのバインドをオプトインする必要があります。 プロパティにマップする前に、ユーザー入力を確認してください。 GET
バインドをオプトインするのは、クエリ文字列やルート値に依存するシナリオに対処する場合に便利です。
GET
要求のプロパティをバインドするには、[BindProperty]
属性の SupportsGet
プロパティを true
に設定します。
[BindProperty(SupportsGet = true)]
詳細については、「ASP.NET Core コミュニティ スタンドアップ: GET ディスカッション (YouTube) でのバインド」を参照してください。
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
OnGetAsync
メソッドの最初の行により、ムービーを選択する LINQ クエリが作成されます。
// using System.Linq;
var movies = from m in _context.Movie
select m;
このクエリは、この時点では "定義されている" だけであり、データベースに対して実行されているわけでは "ありません"。
SearchString
プロパティが null
でも空でもない場合、検索文字列で絞り込むようにムービークエリが変更されます。
if (!string.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.Title.Contains(SearchString));
}
s => s.Title.Contains()
コードはラムダ式です。 ラムダは、メソッド ベースの LINQ クエリで、Where メソッドや Contains
など、標準クエリ演算子メソッドの引数として使用されます。 LINQ クエリは、Where
、Contains
、OrderBy
などのメソッドの呼び出しで定義または変更されたときには実行されません。 クエリ実行は先送りされます。 その具体値が繰り返されるか、ToListAsync
メソッドが呼び出されるまで、式の評価が延ばされます。 詳細については、「クエリ実行」を参照してください。
Note
Contains メソッドは C# コードではなく、データベースで実行されます。 クエリの大文字と小文字の区別は、データベースや照合順序に依存します。 SQL Server では、Contains
は大文字/小文字の区別がない SQL LIKE にマッピングされます。 既定の照合順序での SQLite は、クエリに応じて、大文字と小文字を区別する場合と区別 "しない" 場合が混在します。 大文字と小文字を区別しない SQLite クエリの作成については、次を参照してください。
ムービー ページに移動し、?searchString=Ghost
のようなクエリ文字列を URL に追加します。 たとえば、「 https://localhost:5001/Movies?searchString=Ghost
」のように入力します。 フィルターされたムービーが表示されます。
次のルート テンプレートが Index ページに追加される場合、検索文字列を URL セグメントとして渡すことができます。 たとえば、「 https://localhost:5001/Movies/Ghost
」のように入力します。
@page "{searchString?}"
先のルート制約では、クエリ文字列値の代わりに、ルート データ (URL セグメント) として題名を検索できます。 "{searchString?}"
の ?
は、これが任意のルート パラメーターであることを意味します。
ASP.NET Core ランタイムではモデル バインドを使用し、クエリ文字列 (?searchString=Ghost
) またはルート データ (https://localhost:5001/Movies/Ghost
) から SearchString
プロパティの値が設定されます。 モデル バインドでは、大文字と小文字は区別 "されません"。
ただし、URL を変更してムービーを検索することをユーザーに求めることはできません。 この手順では、ムービーを絞り込むための UI を追加します。 ルート制約 "{searchString?}"
を追加した場合、それを削除します。
Pages/Movies/Index.cshtml
ファイルを開き、次のコードで強調表示されているマークアップを追加します。
@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.*@
HTML <form>
タグでは、次のタグ ヘルパーが使用されます。
- フォーム タグ ヘルパー フォームが提出されると、フィルター文字列がクエリ文字列経由でページ/ムービー/索引ページに送信されます。
- 入力タグ ヘルパー
変更を保存し、フィルターをテストします。
ジャンルで検索する
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
次のコードは、データベースからすべてのジャンルを取得する LINQ クエリです。
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
ジャンルの SelectList
は、別個のジャンルを推定することで作成されます。
Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
ジャンル検索を Razor ページに追加する
Index.cshtml
の <form>
要素を、次のマークアップで強調されている部分のとおりに更新します。
@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>
ジャンルまたはムービーのタイトル、あるいはその両方で検索して、アプリをテストします。
次のステップ
次のセクションでは、ジャンルまたは名前による映画検索が追加されます。
次の強調表示されたコードを 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; }
上のコードでは、次のようになります。
SearchString
: ユーザーが検索テキスト ボックスに入力したテキストが含まれる。SearchString
には、[BindProperty]
属性があります。[BindProperty]
により、プロパティと同じ名前に基づきフォーム値とクエリ文字列がバインドされます。 HTTP GET 要求でのバインドには[BindProperty(SupportsGet = true)]
が必要です。Genres
: ジャンル一覧が含まれる。Genres
により、ユーザーは一覧からジャンルを選択できます。SelectList
にはusing Microsoft.AspNetCore.Mvc.Rendering;
が必要です。MovieGenre
: ユーザーが選択する特定のジャンルが含まれる。 たとえば、"Western (西部劇)" です。Genres
とMovieGenre
は、このチュートリアルで後述します。
警告
セキュリティ上の理由から、ページ モデルのプロパティに対して GET
要求データのバインドをオプトインする必要があります。 プロパティにマップする前に、ユーザー入力を確認してください。 GET
バインドをオプトインするのは、クエリ文字列やルート値に依存するシナリオに対処する場合に便利です。
GET
要求のプロパティをバインドするには、[BindProperty]
属性の SupportsGet
プロパティを true
に設定します。
[BindProperty(SupportsGet = true)]
詳細については、「ASP.NET Core コミュニティ スタンドアップ: GET ディスカッション (YouTube) でのバインド」を参照してください。
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
OnGetAsync
メソッドの最初の行により、ムービーを選択する LINQ クエリが作成されます。
// using System.Linq;
var movies = from m in _context.Movie
select m;
このクエリは、この時点では "定義されている" だけであり、データベースに対して実行されているわけでは "ありません"。
SearchString
プロパティが null でも空でもない場合、検索文字列で絞り込むようにムービークエリが変更されます。
if (!string.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.Title.Contains(SearchString));
}
s => s.Title.Contains()
コードはラムダ式です。 ラムダは、メソッド ベースの LINQ クエリで、Where メソッドや Contains
など、標準クエリ演算子メソッドの引数として使用されます。 LINQ クエリは、Where
、Contains
、OrderBy
などのメソッドの呼び出しで定義または変更されたときには実行されません。 クエリ実行は先送りされます。 その具体値が繰り返されるか、ToListAsync
メソッドが呼び出されるまで、式の評価が延ばされます。 詳細については、「クエリ実行」を参照してください。
Note
Contains メソッドは C# コードではなく、データベースで実行されます。 クエリの大文字と小文字の区別は、データベースや照合順序に依存します。 SQL Server では、Contains
は大文字/小文字の区別がない SQL LIKE にマッピングされます。 既定の照合順序での SQLite は、クエリに応じて、大文字と小文字を区別する場合と区別 "しない" 場合が混在します。 大文字と小文字を区別しない SQLite クエリの作成については、次を参照してください。
ムービー ページに移動し、?searchString=Ghost
のようなクエリ文字列を URL に追加します。 たとえば、「 https://localhost:5001/Movies?searchString=Ghost
」のように入力します。 フィルターされたムービーが表示されます。
次のルート テンプレートが Index ページに追加される場合、検索文字列を URL セグメントとして渡すことができます。 たとえば、「 https://localhost:5001/Movies/Ghost
」のように入力します。
@page "{searchString?}"
先のルート制約では、クエリ文字列値の代わりに、ルート データ (URL セグメント) として題名を検索できます。 "{searchString?}"
の ?
は、これが任意のルート パラメーターであることを意味します。
ASP.NET Core ランタイムではモデル バインドを使用し、クエリ文字列 (?searchString=Ghost
) またはルート データ (https://localhost:5001/Movies/Ghost
) から SearchString
プロパティの値が設定されます。 モデル バインドでは、大文字と小文字は区別 "されません"。
ただし、URL を変更してムービーを検索することをユーザーに求めることはできません。 この手順では、ムービーを絞り込むための UI を追加します。 ルート制約 "{searchString?}"
を追加した場合、それを削除します。
Pages/Movies/Index.cshtml
ファイルを開き、次のコードで強調表示されているマークアップを追加します。
@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.*@
HTML <form>
タグでは、次のタグ ヘルパーが使用されます。
- フォーム タグ ヘルパー フォームが提出されると、フィルター文字列がクエリ文字列経由でページ/ムービー/索引ページに送信されます。
- 入力タグ ヘルパー
変更を保存し、フィルターをテストします。
ジャンルで検索する
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
次のコードは、データベースからすべてのジャンルを取得する LINQ クエリです。
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
ジャンルの SelectList
は、別個のジャンルを推定することで作成されます。
Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
ジャンル検索を Razor ページに追加する
Index.cshtml
の <form>
要素を、次のマークアップで強調されている部分のとおりに更新します。
@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>
ジャンルまたはムービーのタイトル、あるいはその両方で検索して、アプリをテストします。
次のステップ
次のセクションでは、ジャンルまたは名前による映画検索が追加されます。
強調表示されている次の using ステートメントとプロパティを 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; }
上のコードでは、次のようになります。
SearchString
: ユーザーが検索テキスト ボックスに入力したテキストが含まれる。SearchString
には、[BindProperty]
属性があります。[BindProperty]
により、プロパティと同じ名前に基づきフォーム値とクエリ文字列がバインドされます。 HTTP GET 要求でのバインドには[BindProperty(SupportsGet = true)]
が必要です。Genres
: ジャンル一覧が含まれる。Genres
により、ユーザーは一覧からジャンルを選択できます。SelectList
にはusing Microsoft.AspNetCore.Mvc.Rendering;
が必要です。MovieGenre
: ユーザーが選択する特定のジャンルが含まれる。 たとえば、"Western (西部劇)" です。Genres
とMovieGenre
は、このチュートリアルで後述します。
警告
セキュリティ上の理由から、ページ モデルのプロパティに対して GET
要求データのバインドをオプトインする必要があります。 プロパティにマップする前に、ユーザー入力を確認してください。 GET
バインドをオプトインするのは、クエリ文字列やルート値に依存するシナリオに対処する場合に便利です。
GET
要求のプロパティをバインドするには、[BindProperty]
属性の SupportsGet
プロパティを true
に設定します。
[BindProperty(SupportsGet = true)]
詳細については、「ASP.NET Core コミュニティ スタンドアップ: GET ディスカッション (YouTube) でのバインド」を参照してください。
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
OnGetAsync
メソッドの最初の行により、ムービーを選択する LINQ クエリが作成されます。
// using System.Linq;
var movies = from m in _context.Movie
select m;
このクエリは、この時点では "定義されている" だけであり、データベースに対して実行されているわけでは "ありません"。
SearchString
プロパティが null でも空でもない場合、検索文字列で絞り込むようにムービークエリが変更されます。
if (!string.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.Title.Contains(SearchString));
}
s => s.Title.Contains()
コードはラムダ式です。 ラムダは、メソッド ベースの LINQ クエリで、Where メソッドや Contains
など、標準クエリ演算子メソッドの引数として使用されます。 LINQ クエリは、Where
、Contains
、OrderBy
などのメソッドの呼び出しで定義または変更されたときには実行されません。 クエリ実行は先送りされます。 その具体値が繰り返されるか、ToListAsync
メソッドが呼び出されるまで、式の評価が延ばされます。 詳細については、「クエリ実行」を参照してください。
Note
Contains メソッドは C# コードではなく、データベースで実行されます。 クエリの大文字と小文字の区別は、データベースや照合順序に依存します。 SQL Server では、Contains
は大文字/小文字の区別がない SQL LIKE にマッピングされます。 既定の照合順序での SQLite は、クエリに応じて、大文字と小文字を区別する場合と区別 "しない" 場合が混在します。 大文字と小文字を区別しない SQLite クエリの作成については、次を参照してください。
ムービー ページに移動し、?searchString=Ghost
のようなクエリ文字列を URL に追加します。 たとえば、「 https://localhost:5001/Movies?searchString=Ghost
」のように入力します。 フィルターされたムービーが表示されます。
次のルート テンプレートが Index ページに追加される場合、検索文字列を URL セグメントとして渡すことができます。 たとえば、「 https://localhost:5001/Movies/Ghost
」のように入力します。
@page "{searchString?}"
先のルート制約では、クエリ文字列値の代わりに、ルート データ (URL セグメント) として題名を検索できます。 "{searchString?}"
の ?
は、これが任意のルート パラメーターであることを意味します。
ASP.NET Core ランタイムではモデル バインドを使用し、クエリ文字列 (?searchString=Ghost
) またはルート データ (https://localhost:5001/Movies/Ghost
) から SearchString
プロパティの値が設定されます。 モデル バインドでは、大文字と小文字は区別 "されません"。
ただし、URL を変更してムービーを検索することをユーザーに求めることはできません。 この手順では、ムービーを絞り込むための UI を追加します。 ルート制約 "{searchString?}"
を追加した場合、それを削除します。
Pages/Movies/Index.cshtml
ファイルを開き、次のコードで強調表示されているマークアップを追加します。
@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.*@
HTML <form>
タグでは、次のタグ ヘルパーが使用されます。
- フォーム タグ ヘルパー フォームが提出されると、フィルター文字列がクエリ文字列経由でページ/ムービー/索引ページに送信されます。
- 入力タグ ヘルパー
変更を保存し、フィルターをテストします。
ジャンルで検索する
索引ページの OnGetAsync
メソッドを次のコードに変更します。
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();
}
次のコードは、データベースからすべてのジャンルを取得する LINQ クエリです。
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
ジャンルの SelectList
は、別個のジャンルを推定することで作成されます。
Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
ジャンル検索を Razor ページに追加する
Index.cshtml
の<form>
要素を、次のマークアップで強調されている部分のとおりに更新します。@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.*@
ジャンルまたはムービーのタイトル、あるいはその両方で検索して、アプリをテストします。
次のステップ
ASP.NET Core