ASP.NET Core 中的 Razor Pages 路由和应用约定
了解如何使用页面路由和应用模型提供程序约定来控制 Razor Pages 应用中的页面路由、发现和处理。
若要指定页面路由、添加路由段或向路由添加参数,请使用页面的 @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
和相同数量参数的路由与请求 URL 匹配时,会按添加到 PageConventionCollection 的顺序处理路由。
如果可能,请避免依赖于建立的路由处理顺序。 通常,路由会通过 URL 匹配选择正确路由。 如果必须设置路由 Order
属性以便正确路由请求,则应用的路由方案可能会使客户端感到困惑并且难以维护。 应设法简化应用的路由方案。 示例应用需要显式路由处理顺序以使用单个应用来演示几个路由方案。 但是,在生产应用中应尝试避免设置路由 Order
的做法。
Razor Pages 路由和 MVC 控制器路由共享一个实现。 有关 MVC 主题中的路由顺序的信息可在以下位置获得:路由到控制器操作:对属性路由排序。
模型约定
为 IPageConvention 添加委托,以添加应用于 Razor Pages 的模型约定。
将路由模型约定添加到所有页面
使用 Conventions 创建 IPageRouteModelConvention 并将其添加到 IPageConvention 实例集合中,这些实例将在页面路由模型构造过程中应用。
示例应用包含 GlobalTemplatePageRouteModelConvention
类,用于将 {globalTemplate?}
路由模板添加到应用中的所有页面:
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?}"),
}
});
}
}
}
在上述代码中:
- 传递给 Apply 方法的 PageRouteModel。
- PageRouteModel.Selectors 获取选择器计数。
- 添加了一个新的 SelectorModel,其中包含一个 AttributeRouteModel
将 Razor Pages 添加到服务集合时,会添加 Razor Pages 选项,例如添加 Conventions。 有关示例,请参阅示例应用。
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/RouteDataValue
中请求“关于”页面时,由于设置了Order
属性,“RouteDataValue”会加载到RouteData.Values["globalTemplate"]
(Order = 1
) 而不是RouteData.Values["aboutTemplate"]
(Order = 2
) 中。{otherPagesTemplate?}
路由模板显示在前面的代码中。 为{otherPagesTemplate?}
模板指定的Order
为2
。 当使用路由参数请求 Pages/OtherPages 文件夹中的任何页面:例如:
/OtherPages/Page1/xyz
路由数据值
"xyz"
加载到RouteData.Values["globalTemplate"]
(Order = 1
)。由于
Order
属性2
的值较高,未加载具有 (Order = 2
) 的RouteData.Values["otherPagesTemplate"]
。
如果可能,请不要设置 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
中请求示例的“关于”页面,并检查标头以查看结果:
将处理程序模型约定添加到所有页面
使用 Conventions 创建 IPageHandlerModelConvention 并将其添加到 IPageConvention 实例集合中,这些实例将在页面处理程序模型构造过程中应用。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
页面路由操作约定
默认路由模型提供程序派生自 IPageRouteModelProvider,可调用旨在为页面路由配置提供扩展点的约定。
文件夹路由模型约定
使用 AddFolderRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于指定文件夹下的所有页面,会在 PageRouteModel 上调用操作。
示例应用使用 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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果使用路由参数值请求 Pages/OtherPages 文件夹中的任何页面(例如,/OtherPages/Page1/RouteDataValue
)时,由于设置了 Order
属性,因此“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 中,而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
中请求示例的 Page1 页面并检查结果:
页面路由模型约定
使用 AddPageRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于具有指定名称的页面,会在 PageRouteModel 上调用操作。
示例应用使用 AddPageRouteModelConvention
将 {aboutTemplate?}
路由模板添加到“关于”页面:
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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果在 /About/RouteDataValue
中使用路由参数值请求“关于”页面,由于设置了 Order
属性,“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 而不是 RouteData.Values["aboutTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:{port}/About/GlobalRouteValue/AboutRouteValue
中请求示例的“关于”页面并检查结果:
记录器输出显示:
info: SampleApp.Pages.AboutModel[0]
/About/GlobalRouteValue/AboutRouteValue Order = 2 Template = About/{globalTemplate?}/{aboutTemplate?}
使用参数转换程序自定义页面路由
请参阅参数转换器。
配置页面路由
使用 AddPageRoute 配置路由,该路由指向指定页面路径中的页面。 生成的页面链接使用指定的路由。 AddPageRoute 使用 AddPageRouteModelConvention 建立路由。
示例应用为 Contact
Razor 页面创建指向 /TheContactPage
的路由:
options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");
还可在 /
Contact1` 中通过其默认路由访问 Contact
页面。
示例应用的 Contact
页面自定义路由允许使用可选的 text
路由段 ({text?}
)。 该页面还在其 @page
指令中包含此可选段,以便访问者在 /Contact
路由中访问该页面:
@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>
请注意,在呈现的页面中,为联系人链接生成的 URL 反映了已更新的路由:
在常规路由 /Contact
或自定义路由 /TheContactPage
中访问 Contact
页面。 如果提供附加的 text
路由段,该页面会显示所提供的 HTML 编码段:
页面模型操作约定
实现 IPageApplicationModelProvider 的默认页面模型提供程序可调用约定,这些约定旨在为页面模型配置提供扩展点。 在生成和修改页面发现及处理方案时,可使用这些约定。
对于此部分中的示例,示例应用使用 AddHeaderAttribute
类(一个 ResultFilterAttribute)来应用响应标头:
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 可创建和添加 IPageApplicationModelConvention,它对于指定文件夹下的所有页面,会在 PageApplicationModel 实例上调用操作。
示例演示了如何使用 AddFolderApplicationModelConvention
将标头 OtherPagesHeader
添加到应用的 OtherPages 文件夹内的页面:
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
在 localhost:5000/OtherPages/Page1
中请求示例的 Page1 页面,并检查标头以查看结果:
页面应用模型约定
使用 AddPageApplicationModelConvention 可创建和添加 IPageApplicationModelConvention,它对于具有指定名称的页面,会在 PageApplicationModel 上调用操作。
示例演示了如何使用 AddPageApplicationModelConvention
将标头 AboutHeader
添加到“关于”页面:
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
在 localhost:5000/About
中请求示例的“关于”页面,并检查标头以查看结果:
配置筛选器
ConfigureFilter 可配置要应用的指定筛选器。 用户可以实现筛选器类,但示例应用演示了如何在 Lambda 表达式中实现筛选器,该筛选器在后台作为可返回筛选器的工厂实现:
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。
示例应用提供了一个示例,说明如何使用筛选器工厂将具有两个值的标头 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
中请求示例的“关于”页面,并检查标头以查看结果:
MVC 筛选器和页面筛选器 (IPageFilter)
Razor Pages 会忽略 MVC 操作筛选器,因为 Razor Pages 使用处理程序方法。 可以使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器 (IPageFilter) 是应用于 Razor Pages 的一种筛选器。 有关详细信息,请参阅 Razor Pages 的筛选方法。
其他资源
了解如何使用页面路由和应用模型提供程序约定来控制 Razor Pages 应用中的页面路由、发现和处理。
需要为各个页面配置自定义页面路由时,可使用本主题稍后所述的 AddPageRoute 约定配置页面路由。
若要指定页面路由、添加路由段或向路由添加参数,请使用页面的 @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
和相同数量参数的路由与请求 URL 匹配时,会按添加到 PageConventionCollection 的顺序处理路由。
如果可能,请避免依赖于建立的路由处理顺序。 通常,路由会通过 URL 匹配选择正确路由。 如果必须设置路由 Order
属性以便正确路由请求,则应用的路由方案可能会使客户端感到困惑并且难以维护。 应设法简化应用的路由方案。 示例应用需要显式路由处理顺序以使用单个应用来演示几个路由方案。 但是,在生产应用中应尝试避免设置路由 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/RouteDataValue
中请求“关于”页面时,由于设置了Order
属性,“RouteDataValue”会加载到RouteData.Values["globalTemplate"]
(Order = 1
) 而不是RouteData.Values["aboutTemplate"]
(Order = 2
) 中。 - 本主题后面会添加
{otherPagesTemplate?}
路由模板。 为{otherPagesTemplate?}
模板指定的Order
为2
。 当使用路由参数请求 Pages/OtherPages 文件夹中的任何页面(例如,/OtherPages/Page1/RouteDataValue
)时,由于设置了Order
属性,因此“RouteDataValue”会加载到RouteData.Values["globalTemplate"]
(Order = 1
) 中,而不是RouteData.Values["otherPagesTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
将 Razor Pages 添加到 Startup.ConfigureServices
中的服务集合时,会添加 Razor Pages 选项,例如添加 Conventions。 有关示例,请参阅示例应用。
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
在 localhost:5000/About/GlobalRouteValue
中请求示例的“关于”页面并检查结果:
将应用模型约定添加到所有页面
使用 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
中请求示例的“关于”页面,并检查标头以查看结果:
将处理程序模型约定添加到所有页面
使用 Conventions 创建 IPageHandlerModelConvention 并将其添加到 IPageConvention 实例集合中,这些实例将在页面处理程序模型构造过程中应用。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
Startup.cs
:
options.Conventions.Add(new GlobalPageHandlerModelConvention());
页面路由操作约定
默认路由模型提供程序派生自 IPageRouteModelProvider,可调用旨在为页面路由配置提供扩展点的约定。
文件夹路由模型约定
使用 AddFolderRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于指定文件夹下的所有页面,会在 PageRouteModel 上调用操作。
示例应用使用 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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果使用路由参数值请求 Pages/OtherPages 文件夹中的任何页面(例如,/OtherPages/Page1/RouteDataValue
)时,由于设置了 Order
属性,因此“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 中,而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
中请求示例的 Page1 页面并检查结果:
页面路由模型约定
使用 AddPageRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于具有指定名称的页面,会在 PageRouteModel 上调用操作。
示例应用使用 AddPageRouteModelConvention
将 {aboutTemplate?}
路由模板添加到“关于”页面:
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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果在 /About/RouteDataValue
中使用路由参数值请求“关于”页面,由于设置了 Order
属性,“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 而不是 RouteData.Values["aboutTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:5000/About/GlobalRouteValue/AboutRouteValue
中请求示例的“关于”页面并检查结果:
使用参数转换程序自定义页面路由
可以使用参数转换程序自定义 ASP.NET Core 生成的页面路由。 参数转换程序实现 IOutboundParameterTransformer
并转换参数值。 例如,一个自定义 SlugifyParameterTransformer
参数转换程序可将 SubscriptionManagement
路由值更改为 subscription-management
。
PageRouteTransformerConvention
页面路由模型约定将参数转换程序应用于应用中自动生成的页面路由的文件夹和文件名段。 例如,/Pages/SubscriptionManagement/ViewAll.cshtml
处的 Razor Pages 文件会将其路由从 /SubscriptionManagement/ViewAll
重写为 /subscription-management/view-all
。
PageRouteTransformerConvention
仅转换来自 Razor Pages 文件夹和文件名的自动生成页面路由段。 它不会转换使用 @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
中通过默认路由访问“联系人”页面。
示例应用的“联系人”页面自定义路由允许使用可选的 text
路由段 ({text?}
)。 该页面还在其 @page
指令中包含此可选段,以便访问者在 /Contact
路由中访问该页面:
@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>
请注意,在呈现的页面中,为联系人链接生成的 URL 反映了已更新的路由:
在常规路由 /Contact
或自定义路由 /TheContactPage
中访问“联系人”页面。 如果提供附加的 text
路由段,该页面会显示所提供的 HTML 编码段:
页面模型操作约定
实现 IPageApplicationModelProvider 的默认页面模型提供程序可调用约定,这些约定旨在为页面模型配置提供扩展点。 在生成和修改页面发现及处理方案时,可使用这些约定。
对于此部分中的示例,示例应用使用 AddHeaderAttribute
类(一个 ResultFilterAttribute)来应用响应标头:
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 可创建和添加 IPageApplicationModelConvention,它对于指定文件夹下的所有页面,会在 PageApplicationModel 实例上调用操作。
示例演示了如何使用 AddFolderApplicationModelConvention
将标头 OtherPagesHeader
添加到应用的 OtherPages 文件夹内的页面:
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
在 localhost:5000/OtherPages/Page1
中请求示例的 Page1 页面,并检查标头以查看结果:
页面应用模型约定
使用 AddPageApplicationModelConvention 可创建和添加 IPageApplicationModelConvention,它对于具有指定名称的页面,会在 PageApplicationModel 上调用操作。
示例演示了如何使用 AddPageApplicationModelConvention
将标头 AboutHeader
添加到“关于”页面:
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
在 localhost:5000/About
中请求示例的“关于”页面,并检查标头以查看结果:
配置筛选器
ConfigureFilter 可配置要应用的指定筛选器。 用户可以实现筛选器类,但示例应用演示了如何在 Lambda 表达式中实现筛选器,该筛选器在后台作为可返回筛选器的工厂实现:
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。
示例应用提供了一个示例,说明如何使用筛选器工厂将具有两个值的标头 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
中请求示例的“关于”页面,并检查标头以查看结果:
MVC 筛选器和页面筛选器 (IPageFilter)
Razor Pages 会忽略 MVC 操作筛选器,因为 Razor Pages 使用处理程序方法。 可以使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器 (IPageFilter) 是应用于 Razor Pages 的一种筛选器。 有关详细信息,请参阅 Razor Pages 的筛选方法。
其他资源
了解如何使用页面路由和应用模型提供程序约定来控制 Razor Pages 应用中的页面路由、发现和处理。
需要为各个页面配置自定义页面路由时,可使用本主题稍后所述的 AddPageRoute 约定配置页面路由。
若要指定页面路由、添加路由段或向路由添加参数,请使用页面的 @page
指令。 有关详细信息,请参阅自定义路由。
有些保留字不能用作路由段或参数名称。 有关详细信息,请参阅路由:保留的路由名称。
方案 | 示例演示... |
---|---|
模型约定 Conventions.Add
|
将路由模板和标头添加到应用的页面。 |
页面路由操作约定
|
将路由模板添加到某个文件夹中的页面以及单个页面。 |
页面模型操作约定
|
将标头添加到某个文件夹中的多个页面,将标头添加到单个页面,以及配置筛选器工厂以将标头添加到应用的页面。 |
使用 AddRazorPagesOptions 扩展方法向 Startup
类中服务集合的 AddMvc 添加和配置 Razor Pages 约定。 本主题稍后会介绍以下约定示例:
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
和相同数量参数的路由与请求 URL 匹配时,会按添加到 PageConventionCollection 的顺序处理路由。
如果可能,请避免依赖于建立的路由处理顺序。 通常,路由会通过 URL 匹配选择正确路由。 如果必须设置路由 Order
属性以便正确路由请求,则应用的路由方案可能会使客户端感到困惑并且难以维护。 应设法简化应用的路由方案。 示例应用需要显式路由处理顺序以使用单个应用来演示几个路由方案。 但是,在生产应用中应尝试避免设置路由 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/RouteDataValue
中请求“关于”页面时,由于设置了Order
属性,“RouteDataValue”会加载到RouteData.Values["globalTemplate"]
(Order = 1
) 而不是RouteData.Values["aboutTemplate"]
(Order = 2
) 中。 - 本主题后面会添加
{otherPagesTemplate?}
路由模板。 为{otherPagesTemplate?}
模板指定的Order
为2
。 当使用路由参数请求 Pages/OtherPages 文件夹中的任何页面(例如,/OtherPages/Page1/RouteDataValue
)时,由于设置了Order
属性,因此“RouteDataValue”会加载到RouteData.Values["globalTemplate"]
(Order = 1
) 中,而不是RouteData.Values["otherPagesTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
将 MVC 添加到 Startup.ConfigureServices
中的服务集合时,会添加 Razor Pages 选项,例如添加 Conventions。 有关示例,请参阅示例应用。
options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());
在 localhost:5000/About/GlobalRouteValue
中请求示例的“关于”页面并检查结果:
将应用模型约定添加到所有页面
使用 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
中请求示例的“关于”页面,并检查标头以查看结果:
将处理程序模型约定添加到所有页面
使用 Conventions 创建 IPageHandlerModelConvention 并将其添加到 IPageConvention 实例集合中,这些实例将在页面处理程序模型构造过程中应用。
public class GlobalPageHandlerModelConvention
: IPageHandlerModelConvention
{
public void Apply(PageHandlerModel model)
{
// Access the PageHandlerModel
}
}
Startup.cs
:
options.Conventions.Add(new GlobalPageHandlerModelConvention());
页面路由操作约定
默认路由模型提供程序派生自 IPageRouteModelProvider,可调用旨在为页面路由配置提供扩展点的约定。
文件夹路由模型约定
使用 AddFolderRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于指定文件夹下的所有页面,会在 PageRouteModel 上调用操作。
示例应用使用 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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果使用路由参数值请求 Pages/OtherPages 文件夹中的任何页面(例如,/OtherPages/Page1/RouteDataValue
)时,由于设置了 Order
属性,因此“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 中,而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue
中请求示例的 Page1 页面并检查结果:
页面路由模型约定
使用 AddPageRouteModelConvention 可创建和添加 IPageRouteModelConvention,它对于具有指定名称的页面,会在 PageRouteModel 上调用操作。
示例应用使用 AddPageRouteModelConvention
将 {aboutTemplate?}
路由模板添加到“关于”页面:
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
。 这样可确保,当提供单个路由值时,优先将 {globalTemplate?}
的模板(已在本主题的前面部分设置为 1
)作为第一个路由数据值位置。 如果在 /About/RouteDataValue
中使用路由参数值请求“关于”页面,由于设置了 Order
属性,“RouteDataValue”会加载到 RouteData.Values["globalTemplate"]
(Order = 1
) 而不是 RouteData.Values["aboutTemplate"]
(Order = 2
) 中。
尽可能不要将 Order
设置为 Order = 0
。 依赖路由选择正确的路由。
在 localhost:5000/About/GlobalRouteValue/AboutRouteValue
中请求示例的“关于”页面并检查结果:
配置页面路由
使用 AddPageRoute 配置路由,该路由指向指定页面路径中的页面。 生成的页面链接使用指定的路由。 AddPageRoute
使用 AddPageRouteModelConvention
建立路由。
示例应用为 Contact.cshtml
创建指向 /TheContactPage
的路由:
options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");
还可在 /Contact
中通过默认路由访问“联系人”页面。
示例应用的“联系人”页面自定义路由允许使用可选的 text
路由段 ({text?}
)。 该页面还在其 @page
指令中包含此可选段,以便访问者在 /Contact
路由中访问该页面:
@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>
请注意,在呈现的页面中,为联系人链接生成的 URL 反映了已更新的路由:
在常规路由 /Contact
或自定义路由 /TheContactPage
中访问“联系人”页面。 如果提供附加的 text
路由段,该页面会显示所提供的 HTML 编码段:
页面模型操作约定
实现 IPageApplicationModelProvider 的默认页面模型提供程序可调用约定,这些约定旨在为页面模型配置提供扩展点。 在生成和修改页面发现及处理方案时,可使用这些约定。
对于此部分中的示例,示例应用使用 AddHeaderAttribute
类(一个 ResultFilterAttribute)来应用响应标头:
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 可创建和添加 IPageApplicationModelConvention,它对于指定文件夹下的所有页面,会在 PageApplicationModel 实例上调用操作。
示例演示了如何使用 AddFolderApplicationModelConvention
将标头 OtherPagesHeader
添加到应用的 OtherPages 文件夹内的页面:
options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});
在 localhost:5000/OtherPages/Page1
中请求示例的 Page1 页面,并检查标头以查看结果:
页面应用模型约定
使用 AddPageApplicationModelConvention 可创建和添加 IPageApplicationModelConvention,它对于具有指定名称的页面,会在 PageApplicationModel 上调用操作。
示例演示了如何使用 AddPageApplicationModelConvention
将标头 AboutHeader
添加到“关于”页面:
options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
model.Filters.Add(new AddHeaderAttribute(
"AboutHeader", new string[] { "About Header Value" }));
});
在 localhost:5000/About
中请求示例的“关于”页面,并检查标头以查看结果:
配置筛选器
ConfigureFilter 可配置要应用的指定筛选器。 用户可以实现筛选器类,但示例应用演示了如何在 Lambda 表达式中实现筛选器,该筛选器在后台作为可返回筛选器的工厂实现:
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。
示例应用提供了一个示例,说明如何使用筛选器工厂将具有两个值的标头 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
中请求示例的“关于”页面,并检查标头以查看结果:
MVC 筛选器和页面筛选器 (IPageFilter)
Razor Pages 会忽略 MVC 操作筛选器,因为 Razor Pages 使用处理程序方法。 可以使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器 (IPageFilter) 是应用于 Razor Pages 的一种筛选器。 有关详细信息,请参阅 Razor Pages 的筛选方法。