ASP.NET Core での Razor ページのルートとアプリの規則
ページ ルートとアプリ モデル プロバイダーの規則を使用して、Razor ページ アプリでページのルーティング、検出、および処理を制御する方法について説明します。
ページ ルートの指定、ルート セグメントの追加、ルートへのパラメーターの追加を行うには、ページの @page
ディレクティブを使用します。 詳しくは、「カスタム ルート」をご覧ください。
ルート セグメントやパラメーター名として使用できない予約語がいくつかあります。 詳しくは、ルーティング: ルーティングの予約名に関するページをご覧ください。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
シナリオ | サンプルによるデモの内容 |
---|---|
モデルの規則 Conventions.Add |
ルート テンプレートとヘッダーをアプリのページに追加します。 |
ページ ルート アクション規則 | ルート テンプレートをフォルダー内のページおよび単一ページに追加します。 |
ページ モデル アクション規則
|
ヘッダーをフォルダー内のページに追加し、ヘッダーを単一ページに追加し、ヘッダーをアプリのページに追加するようにフィルター ファクトリを構成します。 |
Razor Pages の規則は、RazorPagesOptions を構成する AddRazorPages のオーバーロードを使用して構成されます。 次の規則の例は、このトピックで後述されます。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages(options =>
{
options.Conventions.Add( ... );
options.Conventions.AddFolderRouteModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageRouteModelConvention(
"/About", model => { ... });
options.Conventions.AddPageRoute(
"/Contact", "TheContactPage/{text?}");
options.Conventions.AddFolderApplicationModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageApplicationModelConvention(
"/About", model => { ... });
options.Conventions.ConfigureFilter(model => { ... });
options.Conventions.ConfigureFilter( ... );
});
}
ルートの順番
ルートは、処理 (ルートの照合) に使われる順番 (Order) を指定します。
ルートの順番 | 動作 |
---|---|
-1 | ルートは、他のルートが処理される前に処理されます。 |
0 | 順番が指定されていません (既定値)。 Order を割り当てない (Order = null ) 場合、処理に使われるルートの Order は既定で 0 (ゼロ) になります。 |
1、2、… n | ルートの処理順序を指定します。 |
ルートの処理は、次の規則で定められています。
- ルートは並んだ順番に処理されます (-1, 0, 1, 2, … n)。
- ルートの
Order
が同じ場合は、最初に最も明確なルートが照合され、続けて次に明確なルートが照合されます。 Order
とパラメーター数が同じルートが 1 つの要求 URL と一致した場合、ルートは PageConventionCollection に追加された順番で処理されます。
可能であれば、定められたルートの処理順序に依存しないようにしてください。 通常は、ルーティングによって、URL が一致する正しいルートが選択されます。 要求が正しくルーティングされるようにルートの Order
プロパティを設定する必要がある場合、アプリのルーティング方式がクライアントにとって紛らわしいものとなり、保守が脆弱になる可能性があります。 アプリのルーティング方式を簡略化するよう努めてください。 サンプル アプリでは、1 つのアプリで複数のルーティング シナリオを示すために、ルートの明示的な処理順序が必要です。 ただし、運用環境のアプリでルートの Order
を設定するやり方は避けるようにしてください。
Razor Pages ルーティングと MVC コントローラー ルーティングは、実装を共有します。 MVC のトピックに記載されているルートの順番については、コントローラー アクションへのルーティング: 属性ルートの順序の指定に関するページをご覧ください。
モデルの規則
IPageConvention の委任を追加すると、Razor Pages に適用されるモデルの規則を追加できます。
すべてのページにルート モデル規則を追加する
Conventions を使用すると、IPageRouteModelConvention を作成して、ページ ルート モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
サンプル アプリには、{globalTemplate?}
ルート テンプレートをアプリ内のすべてのページに追加するために GlobalTemplatePageRouteModelConvention
クラスが含まれます。
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;
public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 1,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{globalTemplate?}"),
}
});
}
}
}
上のコードでは以下の操作が行われます。
- PageRouteModel は Apply メソッドに渡されます。
- PageRouteModel.Selectors によって、セレクターの数が取得されます。
- 新しい SelectorModel が追加されます。これには、AttributeRouteModel が含まれています
Razor Pages のオプション (Conventions の追加など) は、Razor Pages がサービス コレクションに追加されると追加されます。 例については、サンプル アプリを参照してください。
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.EntityFrameworkCore;
using SampleApp.Conventions;
using SampleApp.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("InMemoryDb"));
builder.Services.AddRazorPages(options =>
{
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{otherPagesTemplate?}"),
}
});
}
});
options.Conventions.AddPageRouteModelConvention("/About", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{aboutTemplate?}"),
}
});
}
});
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
GlobalTemplatePageRouteModelConvention
クラスについて考えてみましょう。
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;
public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 1,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{globalTemplate?}"),
}
});
}
}
}
AttributeRouteModel の Order プロパティに 1
が設定されます。 これにより、サンプル アプリで次のルートの照合動作が保証されます。
TheContactPage/{text?}
のルート テンプレートは、このトピックの後半で追加されます。Contact Page
ルートには、null
の既定の順序 (Order = 0
) が設定されているため、Order = 1
を含む{globalTemplate?}
ルート テンプレートの前に一致します。{aboutTemplate?}
ルート テンプレートは、前のコードに示されています。{aboutTemplate?}
テンプレートのOrder
には2
が指定されます。 [About] ページが/About/RouteDataValue
で要求されると、"RouteDataValue" はRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれ、Order
プロパティが設定されるためRouteData.Values["aboutTemplate"]
(Order = 2
) には読み込まれません。{otherPagesTemplate?}
ルート テンプレートは、前のコードに示されています。{otherPagesTemplate?}
テンプレートのOrder
には2
が指定されます。 ルート パラメーターを使用して Pages/OtherPages フォルダー内の任意のページが要求されると、次のようになります。たとえば、
/OtherPages/Page1/xyz
のように指定します。ルート データ値
"xyz"
がRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。RouteData.Values["otherPagesTemplate"]
(Order = 2
) は、Order
プロパティ2
の値が大きいため、読み込まれません。
可能な場合は、Order
を設定しないでください。 Order
が設定されていなければ、既定で Order = 0
となります。 ルーティングに依存して、Order
プロパティではなく、正しいルートを選択します。
localhost:{port}/About/GlobalRouteValue
でサンプルの About
ページを要求し、結果を調べます。
サンプル アプリでは、ログ出力にルーティング情報を表示するために、Rick.Docs.Samples.RouteInfo NuGet パッケージが使用されます。 ロガーで localhost:{port}/About/GlobalRouteValue
を使用すると、使用した要求、Order
、テンプレートが表示されます。
info: SampleApp.Pages.AboutModel[0]
/About/GlobalRouteValue Order = 1 Template = About/{globalTemplate?}
すべてのページにアプリ モデル規則を追加する
Conventions を使用すると、IPageApplicationModelConvention を作成して、ページ アプリ モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
この規則やこのトピックで後述されるその他の規則のデモを実行するには、サンプル アプリに AddHeaderAttribute
クラスを含めます。 クラス コンストラクターは、name
文字列と values
文字列配列を受け入れます。 これらの値は、応答ヘッダーを設定するために、その OnResultExecuting
メソッド内で使用されます。 完全クラスは、このトピックで後述される「ページ モデル アクション規則」セクションで示されます。
サンプル アプリでは、AddHeaderAttribute
クラスを使用して、ヘッダー (GlobalHeader
) をアプリ内のすべてのページに追加します。
public class GlobalHeaderPageApplicationModelConvention
: IPageApplicationModelConvention
{
public void Apply(PageApplicationModel model)
{
model.Filters.Add(new AddHeaderAttribute(
"GlobalHeader", new string[] { "Global Header Value" }));
}
}
Program.cs
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("InMemoryDb"));
builder.Services.AddRazorPages(options =>
{
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());
localhost:{port}/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
すべてのページにハンドラー モデル規則を追加する
Conventions を使用すると、IPageHandlerModelConvention を作成して、ページ ハンドラー モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
ページ ルート アクション規則
IPageRouteModelProvider から派生する既定のルート モデル プロバイダーは、ページ ルートを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。
フォルダー ルート モデル規則
AddFolderRouteModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddFolderRouteModelConvention を使用して、{otherPagesTemplate?}
ルート テンプレートを OtherPages フォルダーのページに追加します。
options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{otherPagesTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 ルート パラメーター値 (/OtherPages/Page1/RouteDataValue
など) を使用して Pages/OtherPages フォルダー内のページが要求されると、Order
プロパティが設定されているため、"RouteDataValue" が RouteData.Values["otherPagesTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
でサンプルの Page1 ページを要求し、その結果を調べます。
ページ ルート モデル規則
AddPageRouteModelConvention を使用すると、指定した名前のページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddPageRouteModelConvention
を使用して、{aboutTemplate?}
ルート テンプレートを [About] ページに追加します。
options.Conventions.AddPageRouteModelConvention("/About", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel!.Template,
"{aboutTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 [About] ページが /About/RouteDataValue
にあるルート パラメーター値で要求されると、Order
プロパティが設定されているため、"RouteDataValue" は RouteData.Values["aboutTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:{port}/About/GlobalRouteValue/AboutRouteValue
でサンプルの [About] ページを要求し、その結果を調べます。
ロガーの出力は、次のように表示されます。
info: SampleApp.Pages.AboutModel[0]
/About/GlobalRouteValue/AboutRouteValue Order = 2 Template = About/{globalTemplate?}/{aboutTemplate?}
パラメーター トランスフォーマーを使用してページ ルートをカスタマイズする
「パラメーター トランスフォーマー」を参照してください。
ページ ルートの構成
AddPageRoute を使用すると、指定したページ パスにあるページへのルートを構成できます。 そのページに対して生成されたリンクでは、指定したルートを使用します。 AddPageRoute では、AddPageRouteModelConvention を使用してルートを確立します。
サンプル アプリを使用すると、Contact
Razor Page の /TheContactPage
へのルートが作成されます。
options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");
Contact
ページには、既定のルート経由の /
Contact1` でアクセスすることもできます。
サンプル アプリの Contact
ページへのカスタム ルートを使用すると、省略可能な text
ルート セグメント ({text?}
) が許可されます。 また、訪問者が /Contact
ルートでページにアクセスする場合、ページの @page
ディレクティブにはこの省略可能なセグメントも含まれます。
@page "{text?}"
@model ContactModel
@{
ViewData["Title"] = "Contact";
}
<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>
<address>
One Microsoft Way<br>
Redmond, WA 98052-6399<br>
<abbr title="Phone">P:</abbr>
425.555.0100
</address>
<address>
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
<p>@Model.RouteDataTextTemplateValue</p>
レンダリングされたページの Contact リンク用に生成された URL には、更新されたルートが反映されることに注意してください。
通常のルート (/Contact
) またはカスタム ルート (/TheContactPage
) のいずれかで、Contact
ページにアクセスします。 追加の text
ルート セグメントを指定した場合、ページには指定した HTML エンコードのセグメントが示されます。
ページ モデル アクション規則
IPageApplicationModelProvider を実装する既定のページ モデル プロバイダーは、ページ モデルを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。 これらの規則は、ページ検出をビルドおよび変更したり、シナリオを処理したりするときに便利です。
このセクションの例の場合、サンプル アプリでは、応答ヘッダーを適用する ResultFilterAttribute である、AddHeaderAttribute
クラスを使用します。
public class AddHeaderAttribute : ResultFilterAttribute
{
private readonly string _name;
private readonly string[] _values;
public AddHeaderAttribute(string name, string[] values)
{
_name = name;
_values = values;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_name, _values);
base.OnResultExecuting(context);
}
}
規則を使用して、このサンプルでは、フォルダー内のすべてのページおよび単一ページに属性を適用する方法のデモを実行します。
フォルダー アプリ モデル規則
AddFolderApplicationModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageApplicationModel インスタンスへのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
このサンプルでは、ヘッダー (OtherPagesHeader
) をアプリの OtherPages フォルダー内にあるページに追加して、AddFolderApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
localhost:5000/OtherPages/Page1
でサンプルの Page1 ページを要求し、そのヘッダーを調べて結果を確認します。
ページ アプリ モデル規則
AddPageApplicationModelConvention を使用すると、指定した名前のページを対象に PageApplicationModel へのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
サンプルでは、ヘッダー (AboutHeader
) を [About] ページに追加して、AddPageApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
フィルターの構成
ConfigureFilter では、指定したフィルターを適用するように構成します。 フィルター クラスを実装できますが、サンプル アプリでは、ラムダ式でフィルターを実装する方法を示しています。これは、フィルターを返すファクトリとしてバックグラウンドで実装されます。
options.Conventions.ConfigureFilter(model =>
{
if (model.RelativePath.Contains("OtherPages/Page2"))
{
return new AddHeaderAttribute(
"OtherPagesPage2Header",
new string[] { "OtherPages/Page2 Header Value" });
}
return new EmptyFilter();
});
ページ アプリ モデルは、OtherPages フォルダーの Page2 ページにつながるセグメントの相対パスを確認するために使用されます。 条件を満たすと、ヘッダーが追加されます。 満たさない場合は、EmptyFilter
が適用されます。
EmptyFilter
はアクション フィルターです。 アクション フィルターは Razor Pages によって無視されるため、パスに OtherPages/Page2
が含まれない場合、EmptyFilter
には意図されたような効果はありません。
localhost:5000/OtherPages/Page2
でサンプルの Page2 ページを要求し、そのヘッダーを調べて結果を確認します。
フィルター ファクトリの構成
ConfigureFilter では、すべての Razor Pages にフィルターを適用するように、指定したファクトリを構成します。
サンプル アプリでは、アプリのページに対する 2 つの値と共にヘッダー (FilterFactoryHeader
) を追加して、フィルター ファクトリを使用する例を提供します。
options.Conventions.ConfigureFilter(new AddHeaderWithFactory());
AddHeaderWithFactory.cs
:
public class AddHeaderWithFactory : IFilterFactory
{
// Implement IFilterFactory
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new AddHeaderFilter();
}
private class AddHeaderFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
"FilterFactoryHeader",
new string[]
{
"Filter Factory Header Value 1",
"Filter Factory Header Value 2"
});
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
MVC フィルターとページ フィルター (IPageFilter)
Razor Pages はハンドラー メソッドを使用するため、MVC アクション フィルターは Razor Pages によって無視されます。 使用できるその他の種類の MVC フィルターは次のとおりです。承認、例外、リソース、および結果。 詳細については、「フィルター」トピックを参照してください。
ページ フィルター (IPageFilter) は、Razor Pages に適用されるフィルターの 1 つです。 詳細については、Razor Pages のフィルター メソッドに関するページを参照してください。
その他の技術情報
ページ ルートとアプリ モデル プロバイダーの規則を使用して、Razor ページ アプリでページのルーティング、検出、および処理を制御する方法について説明します。
個別のページにカスタムのページ ルートを構成する必要がある場合、このトピックで後述される「AddPageRoute convention」で、ページへのルーティングを構成します。
ページ ルートの指定、ルート セグメントの追加、ルートへのパラメーターの追加を行うには、ページの @page
ディレクティブを使用します。 詳しくは、「カスタム ルート」をご覧ください。
ルート セグメントやパラメーター名として使用できない予約語がいくつかあります。 詳しくは、ルーティング: ルーティングの予約名に関するページをご覧ください。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
シナリオ | このサンプルでは、次のデモを実行します。 |
---|---|
モデルの規則 Conventions.Add
|
ルート テンプレートとヘッダーをアプリのページに追加します。 |
ページ ルート アクション規則
|
ルート テンプレートをフォルダー内のページおよび単一ページに追加します。 |
ページ モデル アクション規則
|
ヘッダーをフォルダー内のページに追加し、ヘッダーを単一ページに追加し、ヘッダーをアプリのページに追加するようにフィルター ファクトリを構成します。 |
Razor Pages の規則は、Startup.ConfigureServices
で RazorPagesOptions を構成する AddRazorPages のオーバーロードを使用して構成されます。 次の規則の例は、このトピックで後述されます。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.Add( ... );
options.Conventions.AddFolderRouteModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageRouteModelConvention(
"/About", model => { ... });
options.Conventions.AddPageRoute(
"/Contact", "TheContactPage/{text?}");
options.Conventions.AddFolderApplicationModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageApplicationModelConvention(
"/About", model => { ... });
options.Conventions.ConfigureFilter(model => { ... });
options.Conventions.ConfigureFilter( ... );
});
}
ルートの順番
ルートは、処理 (ルートの照合) に使われる順番 (Order) を指定します。
順番 | 動作 |
---|---|
-1 | ルートは、他のルートが処理される前に処理されます。 |
0 | 順番が指定されていません (既定値)。 Order を割り当てない (Order = null ) 場合、処理に使われるルートの Order は既定で 0 (ゼロ) になります。 |
1、2、… n | ルートの処理順序を指定します。 |
ルートの処理は、次の規則で定められています。
- ルートは並んだ順番に処理されます (-1, 0, 1, 2, … n)。
- ルートの
Order
が同じ場合は、最初に最も明確なルートが照合され、続けて次に明確なルートが照合されます。 Order
とパラメーター数が同じルートが 1 つの要求 URL と一致した場合、ルートは PageConventionCollection に追加された順番で処理されます。
可能であれば、定められたルートの処理順序に依存しないようにしてください。 通常は、ルーティングによって、URL が一致する正しいルートが選択されます。 要求が正しくルーティングされるようにルートの Order
プロパティを設定する必要がある場合、アプリのルーティング方式がクライアントにとって紛らわしいものとなり、保守が脆弱になる可能性があります。 アプリのルーティング方式を簡略化するよう努めてください。 サンプル アプリでは、1 つのアプリで複数のルーティング シナリオを示すために、ルートの明示的な処理順序が必要です。 ただし、運用環境のアプリでルートの Order
を設定するやり方は避けるようにしてください。
Razor Pages ルーティングと MVC コントローラー ルーティングは、実装を共有します。 MVC のトピックに記載されているルートの順番については、コントローラー アクションへのルーティング: 属性ルートの順序の指定に関するページをご覧ください。
モデルの規則
IPageConvention の委任を追加すると、Razor Pages に適用されるモデルの規則を追加できます。
すべてのページにルート モデル規則を追加する
Conventions を使用すると、IPageRouteModelConvention を作成して、ページ ルート モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
サンプル アプリでは、{globalTemplate?}
ルート テンプレートをアプリ内のすべてのページに追加します。
public class GlobalTemplatePageRouteModelConvention
: IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 1,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{globalTemplate?}"),
}
});
}
}
}
AttributeRouteModel の Order プロパティに 1
が設定されます。 これにより、サンプル アプリで次のルートの照合動作が保証されます。
TheContactPage/{text?}
のルート テンプレートは、このトピックの後半で追加されます。 連絡先ページのルートには既定の順番null
(Order = 0
) が設定されているため、{globalTemplate?}
ルート テンプレートの前に一致します。{aboutTemplate?}
ルート テンプレートは、このトピックの後半で追加されます。{aboutTemplate?}
テンプレートのOrder
には2
が指定されます。 [About] ページが/About/RouteDataValue
で要求されると、"RouteDataValue" はRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれ、Order
プロパティが設定されるためRouteData.Values["aboutTemplate"]
(Order = 2
) には読み込まれません。{otherPagesTemplate?}
ルート テンプレートは、このトピックの後半で追加されます。{otherPagesTemplate?}
テンプレートのOrder
には2
が指定されます。 ルート パラメーター (/OtherPages/Page1/RouteDataValue
など) を使用して Pages/OtherPages フォルダー内のいずれかのページが要求されると、Order
プロパティが設定されているため、"RouteDataValue" がRouteData.Values["otherPagesTemplate"]
(Order = 2
) ではなくRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
Razor Pages のオプション (Conventions の追加など) は、Razor Pages が Startup.ConfigureServices
のサービス コレクションに追加されたときに追加されます。 例については、サンプル アプリを参照してください。
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
localhost:5000/About/GlobalRouteValue
でサンプルの [About] ページを要求し、その結果を調べます。
すべてのページにアプリ モデル規則を追加する
Conventions を使用すると、IPageApplicationModelConvention を作成して、ページ アプリ モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
この規則やこのトピックで後述されるその他の規則のデモを実行するには、サンプル アプリに AddHeaderAttribute
クラスを含めます。 クラス コンストラクターは、name
文字列と values
文字列配列を受け入れます。 これらの値は、応答ヘッダーを設定するために、その OnResultExecuting
メソッド内で使用されます。 完全クラスは、このトピックで後述される「ページ モデル アクション規則」セクションで示されます。
サンプル アプリでは、AddHeaderAttribute
クラスを使用して、ヘッダー (GlobalHeader
) をアプリ内のすべてのページに追加します。
public class GlobalHeaderPageApplicationModelConvention
: IPageApplicationModelConvention
{
public void Apply(PageApplicationModel model)
{
model.Filters.Add(new AddHeaderAttribute(
"GlobalHeader", new string[] { "Global Header Value" }));
}
}
Startup.cs
:
options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
すべてのページにハンドラー モデル規則を追加する
Conventions を使用すると、IPageHandlerModelConvention を作成して、ページ ハンドラー モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
Startup.cs
:
options.Conventions.Add(new GlobalPageHandlerModelConvention());
ページ ルート アクション規則
IPageRouteModelProvider から派生する既定のルート モデル プロバイダーは、ページ ルートを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。
フォルダー ルート モデル規則
AddFolderRouteModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddFolderRouteModelConvention を使用して、{otherPagesTemplate?}
ルート テンプレートを OtherPages フォルダーのページに追加します。
options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{otherPagesTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 ルート パラメーター値 (/OtherPages/Page1/RouteDataValue
など) を使用して Pages/OtherPages フォルダー内のページが要求されると、Order
プロパティが設定されているため、"RouteDataValue" が RouteData.Values["otherPagesTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
でサンプルの Page1 ページを要求し、その結果を調べます。
ページ ルート モデル規則
AddPageRouteModelConvention を使用すると、指定した名前のページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddPageRouteModelConvention
を使用して、{aboutTemplate?}
ルート テンプレートを [About] ページに追加します。
options.Conventions.AddPageRouteModelConvention("/About", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{aboutTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 [About] ページが /About/RouteDataValue
にあるルート パラメーター値で要求されると、Order
プロパティが設定されているため、"RouteDataValue" は RouteData.Values["aboutTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:5000/About/GlobalRouteValue/AboutRouteValue
でサンプルの [About] ページを要求し、その結果を調べます。
パラメーター トランスフォーマーを使用してページ ルートをカスタマイズする
ASP.NET Core によって生成されたページ ルートは、パラメーター トランスフォーマーを使用してカスタマイズできます。 パラメーター トランスフォーマーは IOutboundParameterTransformer
を実装し、パラメーターの値を変換します。 たとえば、SlugifyParameterTransformer
パラメーター トランスフォーマーでは、SubscriptionManagement
のルート値が subscription-management
に変更されます。
PageRouteTransformerConvention
ページ ルート モデル規則では、アプリで自動的に生成されたページ ルートのフォルダー名とファイル名のセグメントにパラメーター トランスフォーマーを適用します。 たとえば、/Pages/SubscriptionManagement/ViewAll.cshtml
の Razor ページ ファイルには、/SubscriptionManagement/ViewAll
から /subscription-management/view-all
に書き換えられたルートが含まれます。
PageRouteTransformerConvention
では、Razor ページのフォルダー名とファイル名に由来する、自動的に生成されたページ ルートのセグメントのみを変換します。 @page
ディレクティブを使用して追加したルート セグメントは変換されません。 この規則では、AddPageRoute で追加したルートも変換されません。
PageRouteTransformerConvention
は、Startup.ConfigureServices
でオプションとして登録されます。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.Add(
new PageRouteTransformerConvention(
new SlugifyParameterTransformer()));
});
}
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string TransformOutbound(object value)
{
if (value == null) { return null; }
return Regex.Replace(value.ToString(),
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100)).ToLowerInvariant();
}
}
警告
System.Text.RegularExpressions を使用して信頼できない入力を処理するときは、タイムアウトを渡します。 悪意のあるユーザーが RegularExpressions
に入力を提供して、サービス拒否攻撃を行う可能性があります。 RegularExpressions
を使用する ASP.NET Core フレームワーク API は、タイムアウトを渡します。
ページ ルートの構成
AddPageRoute を使用すると、指定したページ パスにあるページへのルートを構成できます。 そのページに対して生成されたリンクでは、指定したルートを使用します。 AddPageRoute
では、AddPageRouteModelConvention
を使用してルートを確立します。
サンプル アプリを使用すると、Contact.cshtml
の /TheContactPage
へのルートが作成されます。
options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");
[Contact] ページには、既定のルート経由の /Contact
でアクセスすることもできます。
サンプル アプリの [Contact] ページに対するカスタム ルートでは、省略可能な text
ルート セグメント ({text?}
) を許可します。 また、訪問者が /Contact
ルートでページにアクセスする場合、ページの @page
ディレクティブにはこの省略可能なセグメントも含まれます。
@page "{text?}"
@model ContactModel
@{
ViewData["Title"] = "Contact";
}
<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>
<address>
One Microsoft Way<br>
Redmond, WA 98052-6399<br>
<abbr title="Phone">P:</abbr>
425.555.0100
</address>
<address>
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
<p>@Model.RouteDataTextTemplateValue</p>
レンダリングされたページの Contact リンク用に生成された URL には、更新されたルートが反映されることに注意してください。
通常のルート (/Contact
) またはカスタム ルート (/TheContactPage
) のいずれかで、[Contact] ページにアクセスします。 追加の text
ルート セグメントを指定した場合、ページには指定した HTML エンコードのセグメントが示されます。
ページ モデル アクション規則
IPageApplicationModelProvider を実装する既定のページ モデル プロバイダーは、ページ モデルを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。 これらの規則は、ページ検出をビルドおよび変更したり、シナリオを処理したりするときに便利です。
このセクションの例の場合、サンプル アプリでは、応答ヘッダーを適用する ResultFilterAttribute である、AddHeaderAttribute
クラスを使用します。
public class AddHeaderAttribute : ResultFilterAttribute
{
private readonly string _name;
private readonly string[] _values;
public AddHeaderAttribute(string name, string[] values)
{
_name = name;
_values = values;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_name, _values);
base.OnResultExecuting(context);
}
}
規則を使用して、このサンプルでは、フォルダー内のすべてのページおよび単一ページに属性を適用する方法のデモを実行します。
フォルダー アプリ モデル規則
AddFolderApplicationModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageApplicationModel インスタンスへのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
このサンプルでは、ヘッダー (OtherPagesHeader
) をアプリの OtherPages フォルダー内にあるページに追加して、AddFolderApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
localhost:5000/OtherPages/Page1
でサンプルの Page1 ページを要求し、そのヘッダーを調べて結果を確認します。
ページ アプリ モデル規則
AddPageApplicationModelConvention を使用すると、指定した名前のページを対象に PageApplicationModel へのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
サンプルでは、ヘッダー (AboutHeader
) を [About] ページに追加して、AddPageApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
フィルターの構成
ConfigureFilter では、指定したフィルターを適用するように構成します。 フィルター クラスを実装できますが、サンプル アプリでは、ラムダ式でフィルターを実装する方法を示しています。これは、フィルターを返すファクトリとしてバックグラウンドで実装されます。
options.Conventions.ConfigureFilter(model =>
{
if (model.RelativePath.Contains("OtherPages/Page2"))
{
return new AddHeaderAttribute(
"OtherPagesPage2Header",
new string[] { "OtherPages/Page2 Header Value" });
}
return new EmptyFilter();
});
ページ アプリ モデルは、OtherPages フォルダーの Page2 ページにつながるセグメントの相対パスを確認するために使用されます。 条件を満たすと、ヘッダーが追加されます。 満たさない場合は、EmptyFilter
が適用されます。
EmptyFilter
はアクション フィルターです。 アクション フィルターは Razor Pages によって無視されるため、パスに OtherPages/Page2
が含まれない場合、EmptyFilter
には意図されたような効果はありません。
localhost:5000/OtherPages/Page2
でサンプルの Page2 ページを要求し、そのヘッダーを調べて結果を確認します。
フィルター ファクトリの構成
ConfigureFilter では、すべての Razor Pages にフィルターを適用するように、指定したファクトリを構成します。
サンプル アプリでは、アプリのページに対する 2 つの値と共にヘッダー (FilterFactoryHeader
) を追加して、フィルター ファクトリを使用する例を提供します。
options.Conventions.ConfigureFilter(new AddHeaderWithFactory());
AddHeaderWithFactory.cs
:
public class AddHeaderWithFactory : IFilterFactory
{
// Implement IFilterFactory
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new AddHeaderFilter();
}
private class AddHeaderFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
"FilterFactoryHeader",
new string[]
{
"Filter Factory Header Value 1",
"Filter Factory Header Value 2"
});
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
MVC フィルターとページ フィルター (IPageFilter)
Razor Pages はハンドラー メソッドを使用するため、MVC アクション フィルターは Razor Pages によって無視されます。 使用できるその他の種類の MVC フィルターは次のとおりです。承認、例外、リソース、および結果。 詳細については、「フィルター」トピックを参照してください。
ページ フィルター (IPageFilter) は、Razor Pages に適用されるフィルターの 1 つです。 詳細については、Razor Pages のフィルター メソッドに関するページを参照してください。
その他の技術情報
ページ ルートとアプリ モデル プロバイダーの規則を使用して、Razor ページ アプリでページのルーティング、検出、および処理を制御する方法について説明します。
個別のページにカスタムのページ ルートを構成する必要がある場合、このトピックで後述される「AddPageRoute convention」で、ページへのルーティングを構成します。
ページ ルートの指定、ルート セグメントの追加、ルートへのパラメーターの追加を行うには、ページの @page
ディレクティブを使用します。 詳しくは、「カスタム ルート」をご覧ください。
ルート セグメントやパラメーター名として使用できない予約語がいくつかあります。 詳しくは、ルーティング: ルーティングの予約名に関するページをご覧ください。
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
シナリオ | このサンプルでは、次のデモを実行します。 |
---|---|
モデルの規則 Conventions.Add
|
ルート テンプレートとヘッダーをアプリのページに追加します。 |
ページ ルート アクション規則
|
ルート テンプレートをフォルダー内のページおよび単一ページに追加します。 |
ページ モデル アクション規則
|
ヘッダーをフォルダー内のページに追加し、ヘッダーを単一ページに追加し、ヘッダーをアプリのページに追加するようにフィルター ファクトリを構成します。 |
Razor ページの規則を追加および構成するには、Startup
クラス内のサービス コレクションの AddMvc に AddRazorPagesOptions 拡張メソッドを使用します。 次の規則の例は、このトピックで後述されます。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.Add( ... );
options.Conventions.AddFolderRouteModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageRouteModelConvention(
"/About", model => { ... });
options.Conventions.AddPageRoute(
"/Contact", "TheContactPage/{text?}");
options.Conventions.AddFolderApplicationModelConvention(
"/OtherPages", model => { ... });
options.Conventions.AddPageApplicationModelConvention(
"/About", model => { ... });
options.Conventions.ConfigureFilter(model => { ... });
options.Conventions.ConfigureFilter( ... );
});
}
ルートの順番
ルートは、処理 (ルートの照合) に使われる順番 (Order) を指定します。
順番 | 動作 |
---|---|
-1 | ルートは、他のルートが処理される前に処理されます。 |
0 | 順番が指定されていません (既定値)。 Order を割り当てない (Order = null ) 場合、処理に使われるルートの Order は既定で 0 (ゼロ) になります。 |
1、2、… n | ルートの処理順序を指定します。 |
ルートの処理は、次の規則で定められています。
- ルートは並んだ順番に処理されます (-1, 0, 1, 2, … n)。
- ルートの
Order
が同じ場合は、最初に最も明確なルートが照合され、続けて次に明確なルートが照合されます。 Order
とパラメーター数が同じルートが 1 つの要求 URL と一致した場合、ルートは PageConventionCollection に追加された順番で処理されます。
可能であれば、定められたルートの処理順序に依存しないようにしてください。 通常は、ルーティングによって、URL が一致する正しいルートが選択されます。 要求が正しくルーティングされるようにルートの Order
プロパティを設定する必要がある場合、アプリのルーティング方式がクライアントにとって紛らわしいものとなり、保守が脆弱になる可能性があります。 アプリのルーティング方式を簡略化するよう努めてください。 サンプル アプリでは、1 つのアプリで複数のルーティング シナリオを示すために、ルートの明示的な処理順序が必要です。 ただし、運用環境のアプリでルートの Order
を設定するやり方は避けるようにしてください。
Razor Pages ルーティングと MVC コントローラー ルーティングは、実装を共有します。 MVC のトピックに記載されているルートの順番については、コントローラー アクションへのルーティング: 属性ルートの順序の指定に関するページをご覧ください。
モデルの規則
IPageConvention の委任を追加すると、Razor Pages に適用されるモデルの規則を追加できます。
すべてのページにルート モデル規則を追加する
Conventions を使用すると、IPageRouteModelConvention を作成して、ページ ルート モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
サンプル アプリでは、{globalTemplate?}
ルート テンプレートをアプリ内のすべてのページに追加します。
public class GlobalTemplatePageRouteModelConvention
: IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 1,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{globalTemplate?}"),
}
});
}
}
}
AttributeRouteModel の Order プロパティに 1
が設定されます。 これにより、サンプル アプリで次のルートの照合動作が保証されます。
TheContactPage/{text?}
のルート テンプレートは、このトピックの後半で追加されます。 連絡先ページのルートには既定の順番null
(Order = 0
) が設定されているため、{globalTemplate?}
ルート テンプレートの前に一致します。{aboutTemplate?}
ルート テンプレートは、このトピックの後半で追加されます。{aboutTemplate?}
テンプレートのOrder
には2
が指定されます。 [About] ページが/About/RouteDataValue
で要求されると、"RouteDataValue" はRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれ、Order
プロパティが設定されるためRouteData.Values["aboutTemplate"]
(Order = 2
) には読み込まれません。{otherPagesTemplate?}
ルート テンプレートは、このトピックの後半で追加されます。{otherPagesTemplate?}
テンプレートのOrder
には2
が指定されます。 ルート パラメーター (/OtherPages/Page1/RouteDataValue
など) を使用して Pages/OtherPages フォルダー内のいずれかのページが要求されると、Order
プロパティが設定されているため、"RouteDataValue" がRouteData.Values["otherPagesTemplate"]
(Order = 2
) ではなくRouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
Razor Pages のオプション (Conventions の追加など) は、MVC が Startup.ConfigureServices
のサービス コレクションに追加されたときに追加されます。 例については、サンプル アプリを参照してください。
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
localhost:5000/About/GlobalRouteValue
でサンプルの [About] ページを要求し、その結果を調べます。
すべてのページにアプリ モデル規則を追加する
Conventions を使用すると、IPageApplicationModelConvention を作成して、ページ アプリ モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
この規則やこのトピックで後述されるその他の規則のデモを実行するには、サンプル アプリに AddHeaderAttribute
クラスを含めます。 クラス コンストラクターは、name
文字列と values
文字列配列を受け入れます。 これらの値は、応答ヘッダーを設定するために、その OnResultExecuting
メソッド内で使用されます。 完全クラスは、このトピックで後述される「ページ モデル アクション規則」セクションで示されます。
サンプル アプリでは、AddHeaderAttribute
クラスを使用して、ヘッダー (GlobalHeader
) をアプリ内のすべてのページに追加します。
public class GlobalHeaderPageApplicationModelConvention
: IPageApplicationModelConvention
{
public void Apply(PageApplicationModel model)
{
model.Filters.Add(new AddHeaderAttribute(
"GlobalHeader", new string[] { "Global Header Value" }));
}
}
Startup.cs
:
options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
すべてのページにハンドラー モデル規則を追加する
Conventions を使用すると、IPageHandlerModelConvention を作成して、ページ ハンドラー モデルの構築中に適用される IPageConvention インスタンスのコレクションに追加できます。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
Startup.cs
:
options.Conventions.Add(new GlobalPageHandlerModelConvention());
ページ ルート アクション規則
IPageRouteModelProvider から派生する既定のルート モデル プロバイダーは、ページ ルートを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。
フォルダー ルート モデル規則
AddFolderRouteModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddFolderRouteModelConvention を使用して、{otherPagesTemplate?}
ルート テンプレートを OtherPages フォルダーのページに追加します。
options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{otherPagesTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 ルート パラメーター値 (/OtherPages/Page1/RouteDataValue
など) を使用して Pages/OtherPages フォルダー内のページが要求されると、Order
プロパティが設定されているため、"RouteDataValue" が RouteData.Values["otherPagesTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
でサンプルの Page1 ページを要求し、その結果を調べます。
ページ ルート モデル規則
AddPageRouteModelConvention を使用すると、指定した名前のページを対象に PageRouteModel へのアクションを呼び出す IPageRouteModelConvention を作成して追加できます。
サンプル アプリでは AddPageRouteModelConvention
を使用して、{aboutTemplate?}
ルート テンプレートを [About] ページに追加します。
options.Conventions.AddPageRouteModelConvention("/About", model =>
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = 2,
Template = AttributeRouteModel.CombineTemplates(
selector.AttributeRouteModel.Template,
"{aboutTemplate?}"),
}
});
}
});
AttributeRouteModel の Order プロパティに 2
が設定されます。 この設定により、1 つのルート値が指定されたときに、(このトピックの前半で 1
に設定した) {globalTemplate?}
のテンプレートが優先的に最初のルート データ値の位置に指定されます。 [About] ページが /About/RouteDataValue
にあるルート パラメーター値で要求されると、Order
プロパティが設定されているため、"RouteDataValue" は RouteData.Values["aboutTemplate"]
(Order = 2
) ではなく RouteData.Values["globalTemplate"]
(Order = 1
) に読み込まれます。
可能な限り、Order
を設定しないでください。これにより、Order = 0
が生じます。 正しいルートの選択には、ルーティングを使用してください。
localhost:5000/About/GlobalRouteValue/AboutRouteValue
でサンプルの [About] ページを要求し、その結果を調べます。
ページ ルートの構成
AddPageRoute を使用すると、指定したページ パスにあるページへのルートを構成できます。 そのページに対して生成されたリンクでは、指定したルートを使用します。 AddPageRoute
では、AddPageRouteModelConvention
を使用してルートを確立します。
サンプル アプリを使用すると、Contact.cshtml
の /TheContactPage
へのルートが作成されます。
options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");
[Contact] ページには、既定のルート経由の /Contact
でアクセスすることもできます。
サンプル アプリの [Contact] ページに対するカスタム ルートでは、省略可能な text
ルート セグメント ({text?}
) を許可します。 また、訪問者が /Contact
ルートでページにアクセスする場合、ページの @page
ディレクティブにはこの省略可能なセグメントも含まれます。
@page "{text?}"
@model ContactModel
@{
ViewData["Title"] = "Contact";
}
<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>
<address>
One Microsoft Way<br>
Redmond, WA 98052-6399<br>
<abbr title="Phone">P:</abbr>
425.555.0100
</address>
<address>
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
<p>@Model.RouteDataTextTemplateValue</p>
レンダリングされたページの Contact リンク用に生成された URL には、更新されたルートが反映されることに注意してください。
通常のルート (/Contact
) またはカスタム ルート (/TheContactPage
) のいずれかで、[Contact] ページにアクセスします。 追加の text
ルート セグメントを指定した場合、ページには指定した HTML エンコードのセグメントが示されます。
ページ モデル アクション規則
IPageApplicationModelProvider を実装する既定のページ モデル プロバイダーは、ページ モデルを構成するための拡張ポイントを提供するようにデザインされた規則を呼び出します。 これらの規則は、ページ検出をビルドおよび変更したり、シナリオを処理したりするときに便利です。
このセクションの例の場合、サンプル アプリでは、応答ヘッダーを適用する ResultFilterAttribute である、AddHeaderAttribute
クラスを使用します。
public class AddHeaderAttribute : ResultFilterAttribute
{
private readonly string _name;
private readonly string[] _values;
public AddHeaderAttribute(string name, string[] values)
{
_name = name;
_values = values;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(_name, _values);
base.OnResultExecuting(context);
}
}
規則を使用して、このサンプルでは、フォルダー内のすべてのページおよび単一ページに属性を適用する方法のデモを実行します。
フォルダー アプリ モデル規則
AddFolderApplicationModelConvention を使用すると、指定したフォルダーの下にあるすべてのページを対象に PageApplicationModel インスタンスへのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
このサンプルでは、ヘッダー (OtherPagesHeader
) をアプリの OtherPages フォルダー内にあるページに追加して、AddFolderApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
localhost:5000/OtherPages/Page1
でサンプルの Page1 ページを要求し、そのヘッダーを調べて結果を確認します。
ページ アプリ モデル規則
AddPageApplicationModelConvention を使用すると、指定した名前のページを対象に PageApplicationModel へのアクションを呼び出す IPageApplicationModelConvention を作成して追加できます。
サンプルでは、ヘッダー (AboutHeader
) を [About] ページに追加して、AddPageApplicationModelConvention
を使用するデモを実行します。
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
フィルターの構成
ConfigureFilter では、指定したフィルターを適用するように構成します。 フィルター クラスを実装できますが、サンプル アプリでは、ラムダ式でフィルターを実装する方法を示しています。これは、フィルターを返すファクトリとしてバックグラウンドで実装されます。
options.Conventions.ConfigureFilter(model =>
{
if (model.RelativePath.Contains("OtherPages/Page2"))
{
return new AddHeaderAttribute(
"OtherPagesPage2Header",
new string[] { "OtherPages/Page2 Header Value" });
}
return new EmptyFilter();
});
ページ アプリ モデルは、OtherPages フォルダーの Page2 ページにつながるセグメントの相対パスを確認するために使用されます。 条件を満たすと、ヘッダーが追加されます。 満たさない場合は、EmptyFilter
が適用されます。
EmptyFilter
はアクション フィルターです。 アクション フィルターは Razor Pages によって無視されるため、パスに OtherPages/Page2
が含まれない場合、EmptyFilter
には意図されたような効果はありません。
localhost:5000/OtherPages/Page2
でサンプルの Page2 ページを要求し、そのヘッダーを調べて結果を確認します。
フィルター ファクトリの構成
ConfigureFilter では、すべての Razor Pages にフィルターを適用するように、指定したファクトリを構成します。
サンプル アプリでは、アプリのページに対する 2 つの値と共にヘッダー (FilterFactoryHeader
) を追加して、フィルター ファクトリを使用する例を提供します。
options.Conventions.ConfigureFilter(new AddHeaderWithFactory());
AddHeaderWithFactory.cs
:
public class AddHeaderWithFactory : IFilterFactory
{
// Implement IFilterFactory
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new AddHeaderFilter();
}
private class AddHeaderFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
"FilterFactoryHeader",
new string[]
{
"Filter Factory Header Value 1",
"Filter Factory Header Value 2"
});
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
localhost:5000/About
でサンプルの [About] ページを要求し、そのヘッダーを調べて結果を確認します。
MVC フィルターとページ フィルター (IPageFilter)
Razor Pages はハンドラー メソッドを使用するため、MVC アクション フィルターは Razor Pages によって無視されます。 使用できるその他の種類の MVC フィルターは次のとおりです。承認、例外、リソース、および結果。 詳細については、「フィルター」トピックを参照してください。
ページ フィルター (IPageFilter) は、Razor Pages に適用されるフィルターの 1 つです。 詳細については、Razor Pages のフィルター メソッドに関するページを参照してください。
その他の技術情報
ASP.NET Core