ASP.NET Core 中的 Razor Pages 路由和應用程式慣例

了解如何使用頁面路由和應用程式模型提供者慣例,來控制 Razor Pages 應用程式中的頁面路由、探索與處理。

若要指定頁面路由、新增路由區段或將參數新增至路由,請使用頁面的 @page 指示詞。 如需詳細資訊,請參閱自訂路由

有無法做為路由區段或參數名稱的保留字。 如需詳細資訊,請參閱路由:保留路由名稱

檢視或下載範例程式碼 \(英文\) (如何下載)

案例 範例會示範
模型慣例

Conventions.Add
將路由範本和標頭新增至應用程式的頁面。
頁面路由動作慣例 將路由範本新增至資料夾中的頁面,以及新增至單一頁面。
頁面模型動作慣例 將標頭新增至資料夾中的頁面、將標頭新增至單一頁面,以及設定篩選條件 Factory 將標頭新增至應用程式的頁面。

Razor Pages 慣例是使用設定 RazorPagesOptionsAddRazorPages 多載來設定。 稍後在本主題會說明下列慣例範例:


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?}"),
                }
            });
        }
    }
}

在上述程式碼中:

將 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?}"),
                }
            });
        }
    }
}

AttributeRouteModelOrder 屬性設定為 1。 這可確保範例應用程式中的下列路由比對行為:

  • 本主題稍後會新增 TheContactPage/{text?} 的路由範本。 Contact Page 路由的預設順序為 null (Order = 0),因此它在具有 Order = 1{globalTemplate?} 路由範本之前比對。

  • {aboutTemplate?} 路由範本會顯示在上述程式碼中。 {aboutTemplate?} 範本會指定 Order2。 在 /About/RouteDataValue 上要求 About 頁面時,由於設定 Order 屬性之故,因此 "RouteDataValue" 會載入至 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["aboutTemplate"] (Order = 2)。

  • {otherPagesTemplate?} 路由範本會顯示在上述程式碼中。 {otherPagesTemplate?} 範本會指定 Order2。 若路由參數要求 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 頁面,並檢查結果:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

範例應用程式會使用 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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the GlobalHeader has been added.

將處理常式模型慣例新增至所有頁面

使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 2。 這可確保在提供單一路由值時,{globalTemplate?} 的範本 (稍早在本主題中設定為 1) 會指定第一個路由資料值位置的優先順序。 如果使用路由參數值 (例如 /OtherPages/Page1/RouteDataValue) 要求 Pages/OtherPages 資料夾中的某個頁面,則由於已設定 Order 屬性,系統會將 "RouteDataValue" 載入到 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["otherPagesTemplate"] (Order = 2)。

盡可能不要設定 Order,這會導致 Order = 0。 依賴路由來選取正確的路由。

localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue 上要求範例的 Page1 頁面,並檢查結果:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

頁面路由模型慣例

使用 AddPageRouteModelConvention 來建立和新增 IPageRouteModelConvention,針對具有指定名稱的頁面在 PageRouteModel 上叫用動作。

範例應用程式會使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 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 上要求範例的 About 頁面,並檢查結果:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

記錄器輸出會顯示:

info: SampleApp.Pages.AboutModel[0]
       /About/GlobalRouteValue/AboutRouteValue   Order = 2 Template = About/{globalTemplate?}/{aboutTemplate?}

使用參數轉換器自訂頁面路由

請參閱參數轉換器

設定頁面路由

使用 AddPageRoute 以設定路由至指定頁面路徑上的頁面。 產生至此頁面的連結會使用指定的路由。 AddPageRoute 使用 AddPageRouteModelConvention 來建立路由。

範例應用程式會為 ContactRazor 頁面建立通往 /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>

請注意,呈現頁面中針對 Contact 連結所產生的 URL 會反映更新的路由:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

請在其一般路由 /Contact 或自訂路由 /TheContactPage 上瀏覽 Contact 頁面。 如果您提供額外的 text 路由區段,該頁面會顯示您提供的 HTML 編碼區段:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

頁面模型動作慣例

實作 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 執行個體上叫用動作。

此範例示範如何將標頭 OtherPagesHeader 新增至應用程式的 OtherPages 資料夾內的頁面來使用 AddFolderApplicationModelConvention

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

localhost:5000/OtherPages/Page1 上要求範例的 Page1 頁面,並檢查標頭來檢視結果:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

頁面應用程式模型慣例

使用 AddPageApplicationModelConvention 來建立和新增 IPageApplicationModelConvention,針對具有指定名稱的頁面在 PageApplicationModel 上叫用動作。

此範例示範如何將標頭 AboutHeader 新增至 About 頁面來使用 AddPageApplicationModelConvention

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

localhost:5000/About 上要求範例的 About 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the AboutHeader has been added.

設定篩選條件

ConfigureFilter 會設定要套用的指定篩選條件。 您可以實作篩選條件類別,但範例應用程式是示範如何在 Lambda 運算式中實作篩選條件,該運算式會在幕後實作為 Factory 以傳回篩選條件:

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 頁面,並檢查標頭來檢視結果:

The OtherPagesPage2Header is added to the response for Page2.

設定篩選條件 Factory

ConfigureFilter 會設定指定的 Factory,以將篩選條件套用至所有 Razor 頁面。

範例應用程式示範如何以應用程式頁面的兩個值新增標頭 FilterFactoryHeader 來使用篩選條件 Factory

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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

MVC 篩選條件和頁面篩選條件 (IPageFilter)

Razor Pages 會忽略 MVC 動作篩選條件,因為 Razor Pages 使用處理常式方法。 其他類型的 MVC 篩選條件可供您使用:AuthorizationExceptionResourceResult。 如需詳細資訊,請參閱篩選條件主題。

頁面篩選條件 (IPageFilter) 是可套用至 Razor Pages 的篩選條件。 如需詳細資訊,請參閱 Razor Pages 的篩選方法

其他資源

了解如何使用頁面路由和應用程式模型提供者慣例,來控制 Razor Pages 應用程式中的頁面路由、探索與處理。

當您需要設定個別頁面的自訂頁面路由時,請使用本主題稍後所述的 AddPageRoute 慣例來設定路由至頁面。

若要指定頁面路由、新增路由區段或將參數新增至路由,請使用頁面的 @page 指示詞。 如需詳細資訊,請參閱自訂路由

有無法做為路由區段或參數名稱的保留字。 如需詳細資訊,請參閱路由:保留路由名稱

檢視或下載範例程式碼 \(英文\) (如何下載)

案例 範例會示範 ...
模型慣例

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
將路由範本和標頭新增至應用程式的頁面。
頁面路由動作慣例
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
將路由範本新增至資料夾中的頁面,以及新增至單一頁面。
頁面模型動作慣例
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter (篩選類別、Lambda 運算式或篩選 Factory)
將標頭新增至資料夾中的頁面、將標頭新增至單一頁面,以及設定篩選條件 Factory 將標頭新增至應用程式的頁面。

Razor Pages 慣例是使用在 Startup.ConfigureServices 中設定 RazorPagesOptionsAddRazorPages 多載來設定。 稍後在本主題會說明下列慣例範例:

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?}"),
                }
            });
        }
    }
}

AttributeRouteModelOrder 屬性設定為 1。 這可確保範例應用程式中的下列路由比對行為:

  • 本主題稍後會新增 TheContactPage/{text?} 的路由範本。 連絡人頁面路由的預設順序為 null (Order = 0),因此會在 {globalTemplate?} 路由範本之前比對。
  • 本主題稍後會新增 {aboutTemplate?} 路由範本。 {aboutTemplate?} 範本會指定 Order2。 在 /About/RouteDataValue 上要求 About 頁面時,由於設定 Order 屬性之故,因此 "RouteDataValue" 會載入至 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["aboutTemplate"] (Order = 2)。
  • 本主題稍後會新增 {otherPagesTemplate?} 路由範本。 {otherPagesTemplate?} 範本會指定 Order2。 如果使用路由參數 (例如 /OtherPages/Page1/RouteDataValue) 要求 Pages/OtherPages 資料夾中的任何頁面,則由於已設定 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 上要求範例的 About 頁面,並檢查結果:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

將應用程式模型慣例新增至所有頁面

使用 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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the GlobalHeader has been added.

將處理常式模型慣例新增至所有頁面

使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 2。 這可確保在提供單一路由值時,{globalTemplate?} 的範本 (稍早在本主題中設定為 1) 會指定第一個路由資料值位置的優先順序。 如果使用路由參數值 (例如 /OtherPages/Page1/RouteDataValue) 要求 Pages/OtherPages 資料夾中的某個頁面,則由於已設定 Order 屬性,系統會將 "RouteDataValue" 載入到 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["otherPagesTemplate"] (Order = 2)。

盡可能不要設定 Order,這會導致 Order = 0。 依賴路由來選取正確的路由。

localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue 上要求範例的 Page1 頁面,並檢查結果:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

頁面路由模型慣例

使用 AddPageRouteModelConvention 來建立和新增 IPageRouteModelConvention,針對具有指定名稱的頁面在 PageRouteModel 上叫用動作。

範例應用程式會使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 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 上要求範例的 About 頁面,並檢查結果:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

使用參數轉換器自訂頁面路由

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,導致拒絕服務 (DoS) 攻擊。 使用 RegularExpressions 傳送逾時的 ASP.NET Core 架構 API。

設定頁面路由

使用 AddPageRoute 以設定路由至指定頁面路徑上的頁面。 頁面的所產生連結會使用您指定的路由。 AddPageRoute 使用 AddPageRouteModelConvention 來建立路由。

範例應用程式會針對 Contact.cshtml 建立通往 /TheContactPage 的路由:

options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");

Contact 頁面也可以透過其預設路由在 /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>

請注意,呈現頁面中針對 Contact 連結所產生的 URL 會反映更新的路由:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

請在其一般路由 /Contact 或自訂路由 /TheContactPage 上瀏覽 Contact 頁面。 如果您提供額外的 text 路由區段,該頁面會顯示您提供的 HTML 編碼區段:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

頁面模型動作慣例

實作 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 執行個體上叫用動作。

此範例示範如何將標頭 OtherPagesHeader 新增至應用程式的 OtherPages 資料夾內的頁面來使用 AddFolderApplicationModelConvention

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

localhost:5000/OtherPages/Page1 上要求範例的 Page1 頁面,並檢查標頭來檢視結果:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

頁面應用程式模型慣例

使用 AddPageApplicationModelConvention 來建立和新增 IPageApplicationModelConvention,針對具有指定名稱的頁面在 PageApplicationModel 上叫用動作。

此範例示範如何將標頭 AboutHeader 新增至 About 頁面來使用 AddPageApplicationModelConvention

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

localhost:5000/About 上要求範例的 About 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the AboutHeader has been added.

設定篩選條件

ConfigureFilter 會設定要套用的指定篩選條件。 您可以實作篩選條件類別,但範例應用程式是示範如何在 Lambda 運算式中實作篩選條件,該運算式會在幕後實作為 Factory 以傳回篩選條件:

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 頁面,並檢查標頭來檢視結果:

The OtherPagesPage2Header is added to the response for Page2.

設定篩選條件 Factory

ConfigureFilter 會設定指定的 Factory,以將篩選條件套用至所有 Razor 頁面。

範例應用程式示範如何以應用程式頁面的兩個值新增標頭 FilterFactoryHeader 來使用篩選條件 Factory

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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

MVC 篩選條件和頁面篩選條件 (IPageFilter)

Razor Pages 會忽略 MVC 動作篩選條件,因為 Razor Pages 使用處理常式方法。 其他類型的 MVC 篩選條件可供您使用:AuthorizationExceptionResourceResult。 如需詳細資訊,請參閱篩選條件主題。

頁面篩選條件 (IPageFilter) 是可套用至 Razor Pages 的篩選條件。 如需詳細資訊,請參閱 Razor Pages 的篩選方法

其他資源

了解如何使用頁面路由和應用程式模型提供者慣例,來控制 Razor Pages 應用程式中的頁面路由、探索與處理。

當您需要設定個別頁面的自訂頁面路由時,請使用本主題稍後所述的 AddPageRoute 慣例來設定路由至頁面。

若要指定頁面路由、新增路由區段或將參數新增至路由,請使用頁面的 @page 指示詞。 如需詳細資訊,請參閱自訂路由

有無法做為路由區段或參數名稱的保留字。 如需詳細資訊,請參閱路由:保留路由名稱

檢視或下載範例程式碼 \(英文\) (如何下載)

案例 範例會示範 ...
模型慣例

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
將路由範本和標頭新增至應用程式的頁面。
頁面路由動作慣例
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
將路由範本新增至資料夾中的頁面,以及新增至單一頁面。
頁面模型動作慣例
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter (篩選類別、Lambda 運算式或篩選 Factory)
將標頭新增至資料夾中的頁面、將標頭新增至單一頁面,以及設定篩選條件 Factory 將標頭新增至應用程式的頁面。

Razor Pages 慣例是 Startup 類別的服務集合上 AddMvcAddRazorPagesOptions 擴充方法來進行新增和設定。 稍後在本主題會說明下列慣例範例:

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?}"),
                }
            });
        }
    }
}

AttributeRouteModelOrder 屬性設定為 1。 這可確保範例應用程式中的下列路由比對行為:

  • 本主題稍後會新增 TheContactPage/{text?} 的路由範本。 連絡人頁面路由的預設順序為 null (Order = 0),因此會在 {globalTemplate?} 路由範本之前比對。
  • 本主題稍後會新增 {aboutTemplate?} 路由範本。 {aboutTemplate?} 範本會指定 Order2。 在 /About/RouteDataValue 上要求 About 頁面時,由於設定 Order 屬性之故,因此 "RouteDataValue" 會載入至 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["aboutTemplate"] (Order = 2)。
  • 本主題稍後會新增 {otherPagesTemplate?} 路由範本。 {otherPagesTemplate?} 範本會指定 Order2。 如果使用路由參數 (例如 /OtherPages/Page1/RouteDataValue) 要求 Pages/OtherPages 資料夾中的任何頁面,則由於已設定 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 上要求範例的 About 頁面,並檢查結果:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

將應用程式模型慣例新增至所有頁面

使用 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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the GlobalHeader has been added.

將處理常式模型慣例新增至所有頁面

使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 2。 這可確保在提供單一路由值時,{globalTemplate?} 的範本 (稍早在本主題中設定為 1) 會指定第一個路由資料值位置的優先順序。 如果使用路由參數值 (例如 /OtherPages/Page1/RouteDataValue) 要求 Pages/OtherPages 資料夾中的某個頁面,則由於已設定 Order 屬性,系統會將 "RouteDataValue" 載入到 RouteData.Values["globalTemplate"] (Order = 1),而不是 RouteData.Values["otherPagesTemplate"] (Order = 2)。

盡可能不要設定 Order,這會導致 Order = 0。 依賴路由來選取正確的路由。

localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue 上要求範例的 Page1 頁面,並檢查結果:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

頁面路由模型慣例

使用 AddPageRouteModelConvention 來建立和新增 IPageRouteModelConvention,針對具有指定名稱的頁面在 PageRouteModel 上叫用動作。

範例應用程式會使用 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?}"),
            }
        });
    }
});

AttributeRouteModelOrder 屬性設定為 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 上要求範例的 About 頁面,並檢查結果:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

設定頁面路由

使用 AddPageRoute 以設定路由至指定頁面路徑上的頁面。 頁面的所產生連結會使用您指定的路由。 AddPageRoute 使用 AddPageRouteModelConvention 來建立路由。

範例應用程式會針對 Contact.cshtml 建立通往 /TheContactPage 的路由:

options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");

Contact 頁面也可以透過其預設路由在 /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>

請注意,呈現頁面中針對 Contact 連結所產生的 URL 會反映更新的路由:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

請在其一般路由 /Contact 或自訂路由 /TheContactPage 上瀏覽 Contact 頁面。 如果您提供額外的 text 路由區段,該頁面會顯示您提供的 HTML 編碼區段:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

頁面模型動作慣例

實作 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 執行個體上叫用動作。

此範例示範如何將標頭 OtherPagesHeader 新增至應用程式的 OtherPages 資料夾內的頁面來使用 AddFolderApplicationModelConvention

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

localhost:5000/OtherPages/Page1 上要求範例的 Page1 頁面,並檢查標頭來檢視結果:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

頁面應用程式模型慣例

使用 AddPageApplicationModelConvention 來建立和新增 IPageApplicationModelConvention,針對具有指定名稱的頁面在 PageApplicationModel 上叫用動作。

此範例示範如何將標頭 AboutHeader 新增至 About 頁面來使用 AddPageApplicationModelConvention

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

localhost:5000/About 上要求範例的 About 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that the AboutHeader has been added.

設定篩選條件

ConfigureFilter 會設定要套用的指定篩選條件。 您可以實作篩選條件類別,但範例應用程式是示範如何在 Lambda 運算式中實作篩選條件,該運算式會在幕後實作為 Factory 以傳回篩選條件:

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 頁面,並檢查標頭來檢視結果:

The OtherPagesPage2Header is added to the response for Page2.

設定篩選條件 Factory

ConfigureFilter 會設定指定的 Factory,以將篩選條件套用至所有 Razor 頁面。

範例應用程式示範如何以應用程式頁面的兩個值新增標頭 FilterFactoryHeader 來使用篩選條件 Factory

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 頁面,並檢查標頭來檢視結果:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

MVC 篩選條件和頁面篩選條件 (IPageFilter)

Razor Pages 會忽略 MVC 動作篩選條件,因為 Razor Pages 使用處理常式方法。 其他類型的 MVC 篩選條件可供您使用:AuthorizationExceptionResourceResult。 如需詳細資訊,請參閱篩選條件主題。

頁面篩選條件 (IPageFilter) 是可套用至 Razor Pages 的篩選條件。 如需詳細資訊,請參閱 Razor Pages 的篩選方法

其他資源