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 인스턴스의 컬렉션에 추가합니다.

샘플 앱은 앱의 모든 페이지에 {globalTemplate?} 경로 템플릿을 추가하는 GlobalTemplatePageRouteModelConvention 클래스를 포함합니다.

using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;

public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel!.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

위의 코드에서

Conventions 추가와 같은 Razor Pages 옵션은 Razor Pages가 서비스 컬렉션에 추가될 때 추가됩니다. 예제는 샘플 앱을 참조하세요.

using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.EntityFrameworkCore;
using SampleApp.Conventions;
using SampleApp.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
                                   options.UseInMemoryDatabase("InMemoryDb"));

builder.Services.AddRazorPages(options =>
   {
       options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

       options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
       {
           var selectorCount = model.Selectors.Count;
           for (var i = 0; i < selectorCount; i++)
           {
               var selector = model.Selectors[i];
               model.Selectors.Add(new SelectorModel
               {
                   AttributeRouteModel = new AttributeRouteModel
                   {
                       Order = 2,
                       Template = AttributeRouteModel.CombineTemplates(
                           selector.AttributeRouteModel!.Template,
                           "{otherPagesTemplate?}"),
                   }
               });
           }
       });

       options.Conventions.AddPageRouteModelConvention("/About", model =>
       {
           var selectorCount = model.Selectors.Count;
           for (var i = 0; i < selectorCount; i++)
           {
               var selector = model.Selectors[i];
               model.Selectors.Add(new SelectorModel
               {
                   AttributeRouteModel = new AttributeRouteModel
                   {
                       Order = 2,
                       Template = AttributeRouteModel.CombineTemplates(
                           selector.AttributeRouteModel!.Template,
                           "{aboutTemplate?}"),
                   }
               });
           }
       });

   });

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

GlobalTemplatePageRouteModelConvention 클래스를 살펴보겠습니다.

using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;

public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel!.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

AttributeRouteModel에 대한 Order 속성을 1로 설정합니다. 이렇게 하면 샘플 앱에서 다음과 같은 경로 일치 동작이 수행됩니다.

  • TheContactPage/{text?}에 대한 경로 템플릿은 이 항목의 뒷부분에 추가되어 있습니다. Contact Page 경로는 기본 순서가 null(Order = 0)이므로 Order = 1{globalTemplate?} 경로 템플릿 이전에 일치됩니다.

  • {aboutTemplate?} 경로 템플릿은 위 코드에 나와 있습니다. {aboutTemplate?} 템플릿이 2Order로 제공됩니다. /About/RouteDataValue에서 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.

  • {otherPagesTemplate?} 경로 템플릿은 이전 코드에 나와 있습니다. {otherPagesTemplate?} 템플릿이 2Order로 제공됩니다. Pages/OtherPages 폴더의 페이지가 경로 매개 변수를 사용하여 요청된 경우:

  • 예를 들어 /OtherPages/Page1/xyz

  • 경로 데이터 값 "xyz"RouteData.Values["globalTemplate"](Order = 1)에 로드됩니다.

  • RouteData.Values["otherPagesTemplate"](Order = 2)은 더 높은 값을 가지므로 Order 속성 2에 로드되지 않습니다.

가능하면 Order를 설정하지 마세요. Order = 0이 설정되지 않은 경우 기본값은 Order입니다. 라우팅을 사용하여 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 메서드에 사용됩니다. 전체 클래스는 항목의 뒷부분에 나오는 페이지 모델 작업 규칙 섹션에서 보여줍니다.

샘플 앱에서는 앱의 모든 페이지에 GlobalHeader 헤더를 추가하는 AddHeaderAttribute 클래스를 사용합니다.

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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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을 사용하여 지정된 폴더의 모든 페이지에 대해 PageRouteModel에 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 AddFolderRouteModelConvention를 사용하여 {otherPagesTemplate?} 경로 템플릿을 OtherPages 폴더의 페이지에 추가합니다.

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel!.Template,
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

AttributeRouteModel에 대한 Order 속성을 2로 설정합니다. 그러면 단일 경로 값을 제공하는 경우 {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 페이지를 요청하고 결과를 검사합니다.

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을 사용하여 지정된 이름을 갖는 페이지의 PageRouteModel에 대해 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 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에서 경로 매개 변수 값을 사용하여 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.

가능하면 Order는 설정하지 않도록 합니다. 설정하면 Order = 0이 됩니다. 라우팅을 사용하여 올바른 경로를 선택합니다.

localhost:{port}/About/GlobalRouteValue/AboutRouteValue에서 샘플의 정보 페이지를 요청하고 결과를 검사합니다.

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를 사용하여 지정된 페이지 경로에 페이지에 대한 경로를 구성합니다. 페이지에 생성된 링크는 지정된 경로를 사용합니다. AddPageRouteAddPageRouteModelConvention을 사용하여 경로를 설정합니다.

샘플 앱은 ContactRazor 페이지의 /TheContactPage에 대한 경로를 만듭니다.

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

Contact 페이지도 기본 경로를 통해 /Contact1`에 도달할 수 있습니다.

Contact 페이지에 대한 샘플 앱의 사용자 지정 경로는 선택적 text 경로 세그먼트({text?})에 허용됩니다. 방문자가 해당 /Contact 경로에 있는 페이지에 액세스하는 경우 페이지에는 해당 @page 지시문에 있는 이 선택적 세그먼트가 포함됩니다.

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

렌더링된 페이지의 연락처 링크에 생성된 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에서 파생되는 기본 페이지 모델 공급자는 페이지 모델을 구성하기 위한 확장성 지점을 제공하도록 설계된 규칙을 호출합니다. 이러한 규칙은 페이지 검색 및 처리 시나리오를 빌드하고 수정하는 경우에 유용합니다.

샘플 앱은 이 섹션의 예제에서 응답 헤더를 적용하는 ResultFilterAttribute라는 AddHeaderAttribute 클래스를 사용합니다.

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

샘플을 규칙을 사용하여 폴더에 있는 모든 페이지 및 단일 페이지에 특성을 적용하는 방법을 보여줍니다.

폴더 앱 모델 규칙

AddFolderApplicationModelConvention을 사용하여 지정된 폴더에 있는 모든 페이지의 PageApplicationModel 인스턴스에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

이 샘플은 OtherPages 폴더 내의 페이지에 OtherPagesHeader 헤더를 추가하여 앱의 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을 사용하여 지정된 이름을 갖는 페이지의 PageApplicationModel에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

샘플은 정보 페이지에 AboutHeader 헤더를 추가하여 AddPageApplicationModelConvention를 사용하는 방법을 보여줍니다.

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

localhost:5000/About에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

필터 구성

ConfigureFilter는 지정된 필터를 적용하도록 구성합니다. 필터 클래스를 구현할 수 있지만 샘플 앱은 람다 식으로 필터를 구현하는 방법을 보여줍니다. 그러면 백그라운드에서 필터를 반환하는 팩터리로 구현됩니다.

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header",
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

페이지 앱 모델은 OtherPages 폴더에 있는 Page2 페이지로 이동하는 세그먼트에 대한 상대 경로를 확인하는 데 사용됩니다. 조건이 통과하는 경우 헤더가 추가됩니다. 그렇지 않으면 EmptyFilter이 적용됩니다.

EmptyFilter작업 필터입니다. Razor Pages에서 작업 필터를 무시하므로 경로에 OtherPages/Page2가 포함되지 않는 경우 의도한 대로 EmptyFilter가 작동하지 않습니다.

localhost:5000/OtherPages/Page2에서 샘플의 Page2 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

The OtherPagesPage2Header is added to the response for 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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

MVC 필터 및 페이지 필터(IPageFilter)

Razor Pages가 처리기 메서드를 사용하므로 MVC 작업 필터는 Razor Pages에서 무시됩니다. 권한 부여, 예외, 리소스결과에 다른 유형의 MVC 필터를 사용할 수 있습니다. 자세한 내용은 필터 항목을 참조하세요.

페이지 필터(IPageFilter)는 Razor Pages에 적용되는 필터입니다. 자세한 내용은 Razor Pages에 대한 필터 메서드를 참조하세요.

추가 리소스

페이지 경로 및 앱 모델 공급자 규칙을 사용하여 Razor Pages 앱에서 페이지 라우팅, 검색 및 처리를 제어하는 방법을 알아봅니다.

개별 페이지에 대한 사용자 지정 페이지 경로를 구성해야 하는 경우 이 항목의 뒷부분에서 설명할 AddPageRoute 규칙을 사용하여 페이지에 대한 라우팅을 구성합니다.

페이지 경로를 지정하거나, 경로 세그먼트를 추가하거나, 경로에 매개 변수를 추가하려면 페이지의 @page 지시문을 사용합니다. 자세한 내용은 사용자 지정 경로를 참조하세요.

경로 세그먼트 또는 매개 변수 이름으로 사용할 수 없는 예약어가 있습니다. 자세한 내용은 라우팅: 예약된 라우팅 이름을 참조 하세요.

샘플 코드 보기 및 다운로드(다운로드 방법)

시나리오 샘플에서는 다음 사항을 보여줍니다.
모델 규칙

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
경로 템플릿 및 헤더를 앱의 페이지에 추가합니다.
페이지 경로 작업 규칙
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
폴더에 있는 페이지 및 단일 페이지에 경로 템플릿을 추가합니다.
페이지 모델 작업 규칙
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter(필터 클래스, 람다 식 또는 필터 팩터리)
폴더의 페이지에 헤더를 추가하고, 단일 페이지에 헤더를 추가하고, 필터 팩터리를 구성하여 헤더를 앱의 페이지에 추가합니다.

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?} 템플릿이 2Order로 제공됩니다. /About/RouteDataValue에서 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.
  • {otherPagesTemplate?} 경로 템플릿은 이 항목의 뒷부분에 추가되어 있습니다. {otherPagesTemplate?} 템플릿이 2Order로 제공됩니다. Pages/OtherPages 폴더의 모든 페이지가 경로 매개 변수(예: /OtherPages/Page1/RouteDataValue)를 사용하여 요청되면Order 속성 설정 때문에 "RouteDataValue"가 RouteData.Values["globalTemplate"](Order = 1)에 로드되고 RouteData.Values["otherPagesTemplate"](Order = 2)에는 로드되지 않습니다.

가능하면 Order는 설정하지 않도록 합니다. 설정하면 Order = 0이 됩니다. 라우팅을 사용하여 올바른 경로를 선택합니다.

Conventions 추가와 같은 Razor Pages 옵션은 Razor Pages가 Startup.ConfigureServices의 서비스 컬렉션에 추가될 때 추가됩니다. 예제는 샘플 앱을 참조하세요.

options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

localhost:5000/About/GlobalRouteValue에서 샘플의 정보 페이지를 요청하고 결과를 검사합니다.

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 메서드에 사용됩니다. 전체 클래스는 항목의 뒷부분에 나오는 페이지 모델 작업 규칙 섹션에서 보여줍니다.

샘플 앱에서는 앱의 모든 페이지에 GlobalHeader 헤더를 추가하는 AddHeaderAttribute 클래스를 사용합니다.

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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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을 사용하여 지정된 폴더의 모든 페이지에 대해 PageRouteModel에 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 AddFolderRouteModelConvention를 사용하여 {otherPagesTemplate?} 경로 템플릿을 OtherPages 폴더의 페이지에 추가합니다.

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

AttributeRouteModel에 대한 Order 속성을 2로 설정합니다. 그러면 단일 경로 값을 제공하는 경우 {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 페이지를 요청하고 결과를 검사합니다.

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을 사용하여 지정된 이름을 갖는 페이지의 PageRouteModel에 대해 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 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에서 경로 매개 변수 값을 사용하여 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.

가능하면 Order는 설정하지 않도록 합니다. 설정하면 Order = 0이 됩니다. 라우팅을 사용하여 올바른 경로를 선택합니다.

localhost:5000/About/GlobalRouteValue/AboutRouteValue에서 샘플의 정보 페이지를 요청하고 결과를 검사합니다.

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에 의해 추가된 경로를 변환하지 않습니다.

PageRouteTransformerConventionStartup.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();
    }
}

Warning

System.Text.RegularExpressions를 사용하여 신뢰할 수 없는 입력을 처리하는 경우 시간 제한을 전달합니다. 악의적인 사용자가 RegularExpressions에 대한 입력을 제공하여 서비스 거부 공격을 일으킬 수 있습니다. RegularExpressions를 사용하는 ASP.NET Core Framework API는 시간 제한을 전달합니다.

페이지 경로 구성

AddPageRoute를 사용하여 지정된 페이지 경로에 페이지에 대한 경로를 구성합니다. 페이지에 생성된 링크는 지정된 경로를 사용합니다. AddPageRouteAddPageRouteModelConvention을 사용하여 경로를 설정합니다.

샘플 앱은 Contact.cshtml에 대한 /TheContactPage의 경로를 만듭니다.

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

연락처 페이지도 기본 경로를 통해 /Contact에 도달할 수 있습니다.

연락처 페이지에 대한 샘플 앱의 사용자 지정 경로는 선택적 text 경로 세그먼트({text?})에 허용됩니다. 방문자가 해당 /Contact 경로에 있는 페이지에 액세스하는 경우 페이지에는 해당 @page 지시문에 있는 이 선택적 세그먼트가 포함됩니다.

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

렌더링된 페이지의 연락처 링크에 생성된 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에서 연락처 페이지를 방문하세요. 추가 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에서 파생되는 기본 페이지 모델 공급자는 페이지 모델을 구성하기 위한 확장성 지점을 제공하도록 설계된 규칙을 호출합니다. 이러한 규칙은 페이지 검색 및 처리 시나리오를 빌드하고 수정하는 경우에 유용합니다.

샘플 앱은 이 섹션의 예제에서 응답 헤더를 적용하는 ResultFilterAttribute라는 AddHeaderAttribute 클래스를 사용합니다.

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

샘플을 규칙을 사용하여 폴더에 있는 모든 페이지 및 단일 페이지에 특성을 적용하는 방법을 보여줍니다.

폴더 앱 모델 규칙

AddFolderApplicationModelConvention을 사용하여 지정된 폴더에 있는 모든 페이지의 PageApplicationModel 인스턴스에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

이 샘플은 OtherPages 폴더 내의 페이지에 OtherPagesHeader 헤더를 추가하여 앱의 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을 사용하여 지정된 이름을 갖는 페이지의 PageApplicationModel에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

샘플은 정보 페이지에 AboutHeader 헤더를 추가하여 AddPageApplicationModelConvention를 사용하는 방법을 보여줍니다.

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

localhost:5000/About에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

필터 구성

ConfigureFilter는 지정된 필터를 적용하도록 구성합니다. 필터 클래스를 구현할 수 있지만 샘플 앱은 람다 식으로 필터를 구현하는 방법을 보여줍니다. 그러면 백그라운드에서 필터를 반환하는 팩터리로 구현됩니다.

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header", 
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

페이지 앱 모델은 OtherPages 폴더에 있는 Page2 페이지로 이동하는 세그먼트에 대한 상대 경로를 확인하는 데 사용됩니다. 조건이 통과하는 경우 헤더가 추가됩니다. 그렇지 않으면 EmptyFilter이 적용됩니다.

EmptyFilter작업 필터입니다. Razor Pages에서 작업 필터를 무시하므로 경로에 OtherPages/Page2가 포함되지 않는 경우 의도한 대로 EmptyFilter가 작동하지 않습니다.

localhost:5000/OtherPages/Page2에서 샘플의 Page2 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

The OtherPagesPage2Header is added to the response for 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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

MVC 필터 및 페이지 필터(IPageFilter)

Razor Pages가 처리기 메서드를 사용하므로 MVC 작업 필터는 Razor Pages에서 무시됩니다. 권한 부여, 예외, 리소스결과에 다른 유형의 MVC 필터를 사용할 수 있습니다. 자세한 내용은 필터 항목을 참조하세요.

페이지 필터(IPageFilter)는 Razor Pages에 적용되는 필터입니다. 자세한 내용은 Razor Pages에 대한 필터 메서드를 참조하세요.

추가 리소스

페이지 경로 및 앱 모델 공급자 규칙을 사용하여 Razor Pages 앱에서 페이지 라우팅, 검색 및 처리를 제어하는 방법을 알아봅니다.

개별 페이지에 대한 사용자 지정 페이지 경로를 구성해야 하는 경우 이 항목의 뒷부분에서 설명할 AddPageRoute 규칙을 사용하여 페이지에 대한 라우팅을 구성합니다.

페이지 경로를 지정하거나, 경로 세그먼트를 추가하거나, 경로에 매개 변수를 추가하려면 페이지의 @page 지시문을 사용합니다. 자세한 내용은 사용자 지정 경로를 참조하세요.

경로 세그먼트 또는 매개 변수 이름으로 사용할 수 없는 예약어가 있습니다. 자세한 내용은 라우팅: 예약된 라우팅 이름을 참조 하세요.

샘플 코드 보기 및 다운로드(다운로드 방법)

시나리오 샘플에서는 다음 사항을 보여줍니다.
모델 규칙

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
경로 템플릿 및 헤더를 앱의 페이지에 추가합니다.
페이지 경로 작업 규칙
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
폴더에 있는 페이지 및 단일 페이지에 경로 템플릿을 추가합니다.
페이지 모델 작업 규칙
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter(필터 클래스, 람다 식 또는 필터 팩터리)
폴더의 페이지에 헤더를 추가하고, 단일 페이지에 헤더를 추가하고, 필터 팩터리를 구성하여 헤더를 앱의 페이지에 추가합니다.

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

AttributeRouteModel에 대한 Order 속성을 1로 설정합니다. 이렇게 하면 샘플 앱에서 다음과 같은 경로 일치 동작이 수행됩니다.

  • TheContactPage/{text?}에 대한 경로 템플릿은 이 항목의 뒷부분에 추가되어 있습니다. 연락처 페이지 경로는 기본 순서가 null(Order = 0)이므로 {globalTemplate?} 경로 템플릿 이전에 일치됩니다.
  • {aboutTemplate?} 경로 템플릿은 이 항목의 뒷부분에 추가되어 있습니다. {aboutTemplate?} 템플릿이 2Order로 제공됩니다. /About/RouteDataValue에서 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.
  • {otherPagesTemplate?} 경로 템플릿은 이 항목의 뒷부분에 추가되어 있습니다. {otherPagesTemplate?} 템플릿이 2Order로 제공됩니다. Pages/OtherPages 폴더의 모든 페이지가 경로 매개 변수(예: /OtherPages/Page1/RouteDataValue)를 사용하여 요청되면Order 속성 설정 때문에 "RouteDataValue"가 RouteData.Values["globalTemplate"](Order = 1)에 로드되고 RouteData.Values["otherPagesTemplate"](Order = 2)에는 로드되지 않습니다.

가능하면 Order는 설정하지 않도록 합니다. 설정하면 Order = 0이 됩니다. 라우팅을 사용하여 올바른 경로를 선택합니다.

Conventions 추가와 같은 Razor Pages 옵션은 MVC가 Startup.ConfigureServices의 서비스 컬렉션에 추가될 때 추가됩니다. 예제는 샘플 앱을 참조하세요.

options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

localhost:5000/About/GlobalRouteValue에서 샘플의 정보 페이지를 요청하고 결과를 검사합니다.

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 메서드에 사용됩니다. 전체 클래스는 항목의 뒷부분에 나오는 페이지 모델 작업 규칙 섹션에서 보여줍니다.

샘플 앱에서는 앱의 모든 페이지에 GlobalHeader 헤더를 추가하는 AddHeaderAttribute 클래스를 사용합니다.

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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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을 사용하여 지정된 폴더의 모든 페이지에 대해 PageRouteModel에 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 AddFolderRouteModelConvention를 사용하여 {otherPagesTemplate?} 경로 템플릿을 OtherPages 폴더의 페이지에 추가합니다.

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

AttributeRouteModel에 대한 Order 속성을 2로 설정합니다. 그러면 단일 경로 값을 제공하는 경우 {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 페이지를 요청하고 결과를 검사합니다.

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을 사용하여 지정된 이름을 갖는 페이지의 PageRouteModel에 대해 작업을 호출하는 IPageRouteModelConvention을 만들고 추가합니다.

샘플 앱에서는 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에서 경로 매개 변수 값을 사용하여 정보 페이지를 요청하는 경우 "RouteDataValue"는 Order 속성 설정으로 인해 RouteData.Values["aboutTemplate"](Order = 2)이 아닌 RouteData.Values["globalTemplate"](Order = 1)으로 로드됩니다.

가능하면 Order는 설정하지 않도록 합니다. 설정하면 Order = 0이 됩니다. 라우팅을 사용하여 올바른 경로를 선택합니다.

localhost:5000/About/GlobalRouteValue/AboutRouteValue에서 샘플의 정보 페이지를 요청하고 결과를 검사합니다.

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를 사용하여 지정된 페이지 경로에 페이지에 대한 경로를 구성합니다. 페이지에 생성된 링크는 지정된 경로를 사용합니다. AddPageRouteAddPageRouteModelConvention을 사용하여 경로를 설정합니다.

샘플 앱은 Contact.cshtml에 대한 /TheContactPage의 경로를 만듭니다.

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

연락처 페이지도 기본 경로를 통해 /Contact에 도달할 수 있습니다.

연락처 페이지에 대한 샘플 앱의 사용자 지정 경로는 선택적 text 경로 세그먼트({text?})에 허용됩니다. 방문자가 해당 /Contact 경로에 있는 페이지에 액세스하는 경우 페이지에는 해당 @page 지시문에 있는 이 선택적 세그먼트가 포함됩니다.

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

렌더링된 페이지의 연락처 링크에 생성된 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에서 연락처 페이지를 방문하세요. 추가 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에서 파생되는 기본 페이지 모델 공급자는 페이지 모델을 구성하기 위한 확장성 지점을 제공하도록 설계된 규칙을 호출합니다. 이러한 규칙은 페이지 검색 및 처리 시나리오를 빌드하고 수정하는 경우에 유용합니다.

샘플 앱은 이 섹션의 예제에서 응답 헤더를 적용하는 ResultFilterAttribute라는 AddHeaderAttribute 클래스를 사용합니다.

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

샘플을 규칙을 사용하여 폴더에 있는 모든 페이지 및 단일 페이지에 특성을 적용하는 방법을 보여줍니다.

폴더 앱 모델 규칙

AddFolderApplicationModelConvention을 사용하여 지정된 폴더에 있는 모든 페이지의 PageApplicationModel 인스턴스에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

이 샘플은 OtherPages 폴더 내의 페이지에 OtherPagesHeader 헤더를 추가하여 앱의 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을 사용하여 지정된 이름을 갖는 페이지의 PageApplicationModel에 대해 작업을 호출하는 IPageApplicationModelConvention을 만들고 추가합니다.

샘플은 정보 페이지에 AboutHeader 헤더를 추가하여 AddPageApplicationModelConvention를 사용하는 방법을 보여줍니다.

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

localhost:5000/About에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

필터 구성

ConfigureFilter는 지정된 필터를 적용하도록 구성합니다. 필터 클래스를 구현할 수 있지만 샘플 앱은 람다 식으로 필터를 구현하는 방법을 보여줍니다. 그러면 백그라운드에서 필터를 반환하는 팩터리로 구현됩니다.

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header", 
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

페이지 앱 모델은 OtherPages 폴더에 있는 Page2 페이지로 이동하는 세그먼트에 대한 상대 경로를 확인하는 데 사용됩니다. 조건이 통과하는 경우 헤더가 추가됩니다. 그렇지 않으면 EmptyFilter이 적용됩니다.

EmptyFilter작업 필터입니다. Razor Pages에서 작업 필터를 무시하므로 경로에 OtherPages/Page2가 포함되지 않는 경우 의도한 대로 EmptyFilter가 작동하지 않습니다.

localhost:5000/OtherPages/Page2에서 샘플의 Page2 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

The OtherPagesPage2Header is added to the response for 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에서 샘플의 정보 페이지를 요청하고 헤더를 검사하여 결과를 확인합니다.

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

MVC 필터 및 페이지 필터(IPageFilter)

Razor Pages가 처리기 메서드를 사용하므로 MVC 작업 필터는 Razor Pages에서 무시됩니다. 권한 부여, 예외, 리소스결과에 다른 유형의 MVC 필터를 사용할 수 있습니다. 자세한 내용은 필터 항목을 참조하세요.

페이지 필터(IPageFilter)는 Razor Pages에 적용되는 필터입니다. 자세한 내용은 Razor Pages에 대한 필터 메서드를 참조하세요.

추가 리소스