作者:Luke Latham
了解如何使用页面路由和应用模型提供程序约定来控制 Razor 页面应用中的页面路由、发现和处理。
需要为各个页面配置自定义页面路由时,可使用本主题稍后所述的 AddPageRoute 约定配置页面路由。
若要指定页路由、添加路由段或向路由添加参数,请使用页的 @page
指令。 有关详细信息,请参阅自定义路由。
有些保留字不能用作路由段或参数名称。 有关详细信息,请参阅路由:保留的路由名称。
场景 | 示例演示... |
---|---|
模型约定 Conventions.Add
|
将路由模板和标头添加到应用的页面。 |
页面路由操作约定
|
将路由模板添加到某个文件夹中的页面以及单个页面。 |
页面模型操作约定
|
将标头添加到某个文件夹中的多个页面,将标头添加到单个页面,以及配置筛选器工厂以将标头添加到应用的页面。 |
使用 AddRazorPagesOptions 扩展方法添加和配置 Razor Pages 约定,以 AddMvc Startup
类中的服务集合。 本主题稍后会介绍以下约定示例:
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages() .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 (路由匹配)。
Order | 行为 |
---|---|
-1 | 在处理其他路由之前处理路由。 |
0 | 未指定顺序(默认值)。 不分配 Order (Order = null )默认情况下,路由 Order 为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?}"), } }); } } }
Order 的 AttributeRouteModel 属性设置为 1
。 这可确保示例应用中的以下路由匹配行为:
TheContactPage/{text?}
的路由模板。 联系人页路由的默认顺序为 null
(Order = 0
),因此它在 {globalTemplate?}
路由模板之前匹配。{aboutTemplate?}
的路由模板。 为 {aboutTemplate?}
模板指定的 Order
为 2
。 当在 /About/RouteDataValue
中请求“关于”页面时,由于设置了 RouteData.Values["globalTemplate"]
属性,“RouteDataValue”会加载到 Order = 1
(RouteData.Values["aboutTemplate"]
) 而不是 Order = 2
(Order
) 中。{otherPagesTemplate?}
的路由模板。 为 {otherPagesTemplate?}
模板指定的 Order
为 2
。 当使用路由参数(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的任何页面时,将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用路由参数值(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用 /About/RouteDataValue
的路由参数值请求 "关于" 页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["aboutTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 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() .AddRazorPagesOptions(options => { options.Conventions.Add( new PageRouteTransformerConvention( new SlugifyParameterTransformer())); }); } public class SlugifyParameterTransformer : IOutboundParameterTransformer { public string TransformOutbound(object value) { if (value == null) { return null; } // Slugify value return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower(); } }
使用 AddPageRoute 配置指向指定页面路径中的页面的路由。 生成的页面链接使用指定的路由。 AddPageRoute
使用 AddPageRouteModelConvention
建立路由。
示例应用为 /TheContactPage
Contact.cshtml创建指向 的路由:
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
中请求示例的“关于”页面,并检查标头以查看结果:
Razor 页面会忽略 MVC 操作筛选器,因为 Razor 页面使用处理程序方法。 可使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器(IPageFilter)是应用于 Razor Pages 的筛选器。 有关详细信息,请参阅 Razor 页面的筛选方法。
了解如何使用页面路由和应用模型提供程序约定来控制 Razor 页面应用中的页面路由、发现和处理。
需要为各个页面配置自定义页面路由时,可使用本主题稍后所述的 AddPageRoute 约定配置页面路由。
若要指定页路由、添加路由段或向路由添加参数,请使用页的 @page
指令。 有关详细信息,请参阅自定义路由。
有些保留字不能用作路由段或参数名称。 有关详细信息,请参阅路由:保留的路由名称。
场景 | 示例演示... |
---|---|
模型约定 Conventions.Add
|
将路由模板和标头添加到应用的页面。 |
页面路由操作约定
|
将路由模板添加到某个文件夹中的页面以及单个页面。 |
页面模型操作约定
|
将标头添加到某个文件夹中的多个页面,将标头添加到单个页面,以及配置筛选器工厂以将标头添加到应用的页面。 |
使用 AddRazorPagesOptions 扩展方法添加和配置 Razor Pages 约定,以 AddMvc Startup
类中的服务集合。 本主题稍后会介绍以下约定示例:
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 (路由匹配)。
Order | 行为 |
---|---|
-1 | 在处理其他路由之前处理路由。 |
0 | 未指定顺序(默认值)。 不分配 Order (Order = null )默认情况下,路由 Order 为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?}"), } }); } } }
Order 的 AttributeRouteModel 属性设置为 1
。 这可确保示例应用中的以下路由匹配行为:
TheContactPage/{text?}
的路由模板。 联系人页路由的默认顺序为 null
(Order = 0
),因此它在 {globalTemplate?}
路由模板之前匹配。{aboutTemplate?}
的路由模板。 为 {aboutTemplate?}
模板指定的 Order
为 2
。 当在 /About/RouteDataValue
中请求“关于”页面时,由于设置了 RouteData.Values["globalTemplate"]
属性,“RouteDataValue”会加载到 Order = 1
(RouteData.Values["aboutTemplate"]
) 而不是 Order = 2
(Order
) 中。{otherPagesTemplate?}
的路由模板。 为 {otherPagesTemplate?}
模板指定的 Order
为 2
。 当使用路由参数(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的任何页面时,将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用路由参数值(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用 /About/RouteDataValue
的路由参数值请求 "关于" 页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["aboutTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 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.AddMvc() .AddRazorPagesOptions(options => { options.Conventions.Add( new PageRouteTransformerConvention( new SlugifyParameterTransformer())); }); } public class SlugifyParameterTransformer : IOutboundParameterTransformer { public string TransformOutbound(object value) { if (value == null) { return null; } // Slugify value return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower(); } }
使用 AddPageRoute 配置指向指定页面路径中的页面的路由。 生成的页面链接使用指定的路由。 AddPageRoute
使用 AddPageRouteModelConvention
建立路由。
示例应用为 /TheContactPage
Contact.cshtml创建指向 的路由:
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
中请求示例的“关于”页面,并检查标头以查看结果:
Razor 页面会忽略 MVC 操作筛选器,因为 Razor 页面使用处理程序方法。 可使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器(IPageFilter)是应用于 Razor Pages 的筛选器。 有关详细信息,请参阅 Razor 页面的筛选方法。
了解如何使用页面路由和应用模型提供程序约定来控制 Razor 页面应用中的页面路由、发现和处理。
需要为各个页面配置自定义页面路由时,可使用本主题稍后所述的 AddPageRoute 约定配置页面路由。
若要指定页路由、添加路由段或向路由添加参数,请使用页的 @page
指令。 有关详细信息,请参阅自定义路由。
有些保留字不能用作路由段或参数名称。 有关详细信息,请参阅路由:保留的路由名称。
场景 | 示例演示... |
---|---|
模型约定 Conventions.Add
|
将路由模板和标头添加到应用的页面。 |
页面路由操作约定
|
将路由模板添加到某个文件夹中的页面以及单个页面。 |
页面模型操作约定
|
将标头添加到某个文件夹中的多个页面,将标头添加到单个页面,以及配置筛选器工厂以将标头添加到应用的页面。 |
使用 AddRazorPagesOptions 扩展方法添加和配置 Razor Pages 约定,以 AddMvc Startup
类中的服务集合。 本主题稍后会介绍以下约定示例:
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 (路由匹配)。
Order | 行为 |
---|---|
-1 | 在处理其他路由之前处理路由。 |
0 | 未指定顺序(默认值)。 不分配 Order (Order = null )默认情况下,路由 Order 为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?}"), } }); } } }
Order 的 AttributeRouteModel 属性设置为 1
。 这可确保示例应用中的以下路由匹配行为:
TheContactPage/{text?}
的路由模板。 联系人页路由的默认顺序为 null
(Order = 0
),因此它在 {globalTemplate?}
路由模板之前匹配。{aboutTemplate?}
的路由模板。 为 {aboutTemplate?}
模板指定的 Order
为 2
。 当在 /About/RouteDataValue
中请求“关于”页面时,由于设置了 RouteData.Values["globalTemplate"]
属性,“RouteDataValue”会加载到 Order = 1
(RouteData.Values["aboutTemplate"]
) 而不是 Order = 2
(Order
) 中。{otherPagesTemplate?}
的路由模板。 为 {otherPagesTemplate?}
模板指定的 Order
为 2
。 当使用路由参数(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的任何页面时,将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用路由参数值(例如 /OtherPages/Page1/RouteDataValue
)请求Pages/OtherPages文件夹中的页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["otherPagesTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 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?}"), } }); } });
Order 的 AttributeRouteModel 属性设置为 2
。 这可确保在提供单个路由值时,将 {globalTemplate?}
的模板(在主题中设置为 1
)被授予第一个路由数据值位置的优先级。 如果使用 /About/RouteDataValue
的路由参数值请求 "关于" 页,则将 "RouteDataValue" 加载到 RouteData.Values["globalTemplate"]
(Order = 1
),而不是 RouteData.Values["aboutTemplate"]
(Order = 2
),因为设置 Order
属性。
请尽可能不要将 Order
设置为 Order = 0
。 依赖 "路由" 选择正确的路由。
在 localhost:5000/About/GlobalRouteValue/AboutRouteValue
中请求示例的“关于”页面并检查结果:
使用 AddPageRoute 配置指向指定页面路径中的页面的路由。 生成的页面链接使用指定的路由。 AddPageRoute
使用 AddPageRouteModelConvention
建立路由。
示例应用为 /TheContactPage
Contact.cshtml创建指向 的路由:
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
中请求示例的“关于”页面,并检查标头以查看结果:
Razor 页面会忽略 MVC 操作筛选器,因为 Razor 页面使用处理程序方法。 可使用其他类型的 MVC 筛选器:授权、异常、资源和结果。 有关详细信息,请参阅筛选器主题。
页面筛选器(IPageFilter)是应用于 Razor Pages 的筛选器。 有关详细信息,请参阅 Razor 页面的筛选方法。