Соглашения для маршрутов и приложений Razor Pages в ASP.NET Core

Узнайте, как использовать соглашения поставщика модели маршрутов и приложений страниц для управления маршрутизацией, обнаружением и обработкой страниц в приложениях Razor Pages.

Чтобы указать маршрут страницы, добавить сегменты маршрута или добавить параметры в маршрут, используйте директиву @page страницы. Дополнительные сведения см. в разделе Пользовательские маршруты.

Существуют зарезервированные слова, которые нельзя использовать в качестве сегментов маршрутов или имен параметров. Дополнительные сведения см. в статье "Маршрутизация: зарезервированные имена маршрутизации".

Просмотреть или скачать образец кода (описание загрузки)

Сценарий Этот пример демонстрирует следующие приемы.
Соглашения для моделей

Conventions.Add
Добавление шаблона маршрута и заголовка к страницам приложения.
Соглашения для действий с маршрутами страниц Добавление шаблона маршрута к страницам в папке и к одной странице.
Соглашения для действий модели страниц Добавление заголовка к страницам в папке, добавление заголовка к одной странице и настройка фабрики фильтров для добавления заголовка к страницам приложения.

Соглашения Razor Pages настраиваются с помощью перегрузки AddRazorPages, которая настраивает RazorPagesOptions. Следующие примеры соглашений описаны далее в этом разделе:


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, сначала сопоставляется наиболее конкретный маршрут, а затем более общие.
  • Если URL-адресу запроса соответствуют маршруты с одинаковым значением свойства Order и одинаковым количеством параметров, они обрабатываются в том порядке, в котором были добавлены в коллекцию 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, такие как добавление Conventions, добавляются при добавлении Razor Pages в коллекцию служб. Пример см. в образце приложения.

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

var builder = WebApplication.CreateBuilder(args);

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

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

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

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

   });

var app = builder.Build();

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

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

Давайте рассмотрим класс GlobalTemplatePageRouteModelConvention:

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

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

Свойству Order для AttributeRouteModel задано значение 1. Это обеспечивает описанное ниже поведение сопоставления маршрутов в примере приложения.

  • Шаблон маршрута для TheContactPage/{text?} добавляется далее в этом разделе. Маршрут Contact Page по умолчанию имеет порядок null (Order = 0), поэтому он сопоставляется до шаблона маршрута {globalTemplate?} с порядком Order = 1.

  • Шаблон маршрута {aboutTemplate?} показан в приведенном выше коде. Шаблону {aboutTemplate?} задано свойство Order, равное 2. При запросе страницы About по адресу /About/RouteDataValue значение RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

  • Шаблон маршрута {otherPagesTemplate?} показан в приведенном выше коде. Шаблону {otherPagesTemplate?} задано свойство Order, равное 2. При запросе любой страницы в парке Pages/OtherPages с параметром маршрута:

  • Например /OtherPages/Page1/xyz.

  • Значение "xyz" из данных маршрута загружается в RouteData.Values["globalTemplate"] (Order = 1).

  • RouteData.Values["otherPagesTemplate"] с порядком (Order = 2) не загружается из-за того, что свойство 2 в Order имеет более высокое значение.

По возможности не устанавливайте параметр Order. Если для Order не задано значение, по умолчанию используется Order = 0. Для выбора правильного маршрута следует использовать маршрутизацию, а не свойство Order.

Запросите страницу About из примера по адресу localhost:{port}/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.

Этот пример приложения использует пакет NuGet Rick.Docs.Samples.RouteInfo для отображения сведений о маршрутизации в выходных данных для ведения журнала. При использовании 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());

Запросите страницу About по адресу 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, чтобы создать и добавить интерфейс IPageRouteModelConvention, вызывающий действие в классе PageRouteModel для всех страниц в указанной папке.

Пример приложения использует AddFolderRouteModelConvention для добавления шаблона маршрута {otherPagesTemplate?} к страницам в папке OtherPages:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы в папке Pages/OtherPages со значением параметра маршрута (например, /OtherPages/Page1/RouteDataValue), RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["otherPagesTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue из примера и проверьте результат:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы About со значением параметра маршрута по адресу /About/RouteDataValue, RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу About по адресу 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, чтобы настроить маршрут к странице по указанному пути страницы. Созданные ссылки на страницу будут использовать заданный маршрут. Для установления маршрута метод AddPageRoute использует AddPageRouteModelConvention.

Этот пример приложения создает маршрут к /TheContactPage для страницы ContactRazor:

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

На страницу Contact также можно перейти по адресу /Contact1` через маршрут по умолчанию.

Настраиваемый маршрут на страницу Contact в этом примере приложения позволяет использовать необязательный сегмент маршрута text ({text?}). Страница также включает этот необязательный сегмент в своей директиве @page на случай, если посетитель переходит на страницу по маршруту /Contact:

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

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

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

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

<p>@Model.RouteDataTextTemplateValue</p>

Обратите внимание, что URL-адрес, созданный для ссылки Contact на отображенной странице, отражает обновленный маршрут:

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 по ее обычному маршруту /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, использует соглашения, создающие точки расширения для настройки моделей страниц. Эти соглашения полезны при создании и изменении для обнаружения и обработки страниц.

В примерах этого раздела образец приложения использует класс AddHeaderAttribute, который является ResultFilterAttribute и применяет заголовок ответа:

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

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

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

Образец показывает использование соглашений для применения атрибута ко всем страницам в папке и к одной странице.

Соглашение для модели приложений папки

Используйте метод AddFolderApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в экземплярах PageApplicationModel для всех страниц в указанной папке.

Пример демонстрирует использование AddFolderApplicationModelConvention путем добавления заголовка OtherPagesHeader к страницам в папке OtherPages приложения:

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

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1 из примера и посмотрите заголовки, чтобы проверить результат:

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

Соглашение для модели приложений страницы

Используйте метод AddPageApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в классе PageApplicationModel для страницы с указанным именем.

Пример демонстрирует использование AddPageApplicationModelConvention путем добавления заголовка AboutHeader на страницу About:

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

Запросите страницу About по адресу 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();
});

Модель приложений страницы используется для проверки относительного пути на наличие сегментов, ведущих к странице Page2 в папке OtherPages. Если условие выполняется, добавляется заголовок. Если нет, применяется EmptyFilter.

EmptyFilter является фильтром действий. Так как в Razor Pages фильтры действий не учитываются, EmptyFilter не оказывает действия, как и задумано, если путь не содержит OtherPages/Page2.

Запросите страницу Page2 по адресу localhost:5000/OtherPages/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;
        }
    }
}

Запросите страницу About по адресу localhost:5000/About из примера и посмотрите заголовки, чтобы проверить результат:

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

Фильтры MVC и фильтр страниц (IPageFilter)

Фильтры действий MVC игнорируются в Razor Pages, так как 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 настраиваются с помощью перегрузки AddRazorPages, которая настраивает RazorPagesOptions в Startup.ConfigureServices. Следующие примеры соглашений описаны далее в этом разделе:

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, сначала сопоставляется наиболее конкретный маршрут, а затем более общие.
  • Если URL-адресу запроса соответствуют маршруты с одинаковым значением свойства Order и одинаковым количеством параметров, они обрабатываются в том порядке, в котором были добавлены в коллекцию PageConventionCollection.

По возможности старайтесь не использовать строго определенный порядок обработки маршрутов. Как правило, при маршрутизации правильный маршрут выбирается посредством сопоставления URL-адресов. Если для правильной маршрутизации запросов необходимо задать свойства Order маршрута, схема маршрутизации приложения, скорее всего, будет малопонятна клиентам и сложна в обслуживании. Старайтесь упростить схему маршрутизации приложения. В примере приложения требуется явно определенный порядок обработки маршрутов для демонстрации нескольких сценариев маршрутизации на основе одного приложения. Однако в рабочих приложениях следует избегать задания свойства Order для маршрутов.

Средства маршрутизации в Razor Pages и контроллере MVC имеют общую реализацию. Сведения о порядке маршрута в разделах MVC доступны в разделе "Маршрутизация для действий контроллера: упорядочивание маршрутов атрибутов".

Соглашения для моделей

Добавьте делегат для IPageConvention, чтобы добавить соглашения для модели, применяемые к Razor Pages.

Добавление соглашения для модели маршрутов ко всем страницам

Используйте свойство Conventions, чтобы создать и добавить IPageRouteModelConvention в коллекцию экземпляров IPageConvention, которые применяются при формировании модели маршрутов страниц.

В примере приложения шаблон маршрута {globalTemplate?} добавляется ко всем страницам приложения:

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

Свойству Order для AttributeRouteModel задано значение 1. Это обеспечивает описанное ниже поведение сопоставления маршрутов в примере приложения.

  • Шаблон маршрута для TheContactPage/{text?} добавляется далее в разделе. Маршрут страницы Contact по умолчанию имеет порядок null (Order = 0), поэтому он сопоставляется до шаблона маршрута {globalTemplate?}.
  • Шаблон маршрута {aboutTemplate?} добавляется далее в разделе. Шаблону {aboutTemplate?} задано свойство Order, равное 2. При запросе страницы About по адресу /About/RouteDataValue значение RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.
  • Шаблон маршрута {otherPagesTemplate?} добавляется далее в разделе. Шаблону {otherPagesTemplate?} задано свойство Order, равное 2. При запросе любой страницы в папке Pages/OtherPages с параметром маршрута (например, /OtherPages/Page1/RouteDataValue), RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["otherPagesTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Параметры Razor Pages, такие как добавление Conventions, добавляются при добавлении Razor Pages в коллекцию служб в Startup.ConfigureServices. Пример см. в образце приложения.

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

Запросите страницу About по адресу 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 для задания заголовка ответа. Класс показан полностью в разделе Соглашения для действий модели страниц далее.

Пример приложения использует класс 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());

Запросите страницу About по адресу 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, чтобы создать и добавить интерфейс IPageRouteModelConvention, вызывающий действие в классе PageRouteModel для всех страниц в указанной папке.

Пример приложения использует AddFolderRouteModelConvention для добавления шаблона маршрута {otherPagesTemplate?} к страницам в папке OtherPages:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы в папке Pages/OtherPages со значением параметра маршрута (например, /OtherPages/Page1/RouteDataValue), RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["otherPagesTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue из примера и проверьте результат:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы About со значением параметра маршрута по адресу /About/RouteDataValue, RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу About по адресу 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 применяет преобразователь параметров к сегментам имен папок и файлов автоматически создаваемых маршрутов страниц в приложении. Например, для файла Razor Pages по пути /Pages/SubscriptionManagement/ViewAll.cshtml маршрут меняется с /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, что делает возможными атаки типа "отказ в обслуживании". API платформы ASP.NET Core, использующие RegularExpressions, передают время ожидания.

Настройка маршрута страницы

Используйте метод AddPageRoute, чтобы настроить маршрут к странице по указанному пути страницы. Созданные ссылки на страницу будут использовать заданный вами маршрут. Для установления маршрута метод AddPageRoute использует AddPageRouteModelConvention.

Пример приложения создает маршрут к /TheContactPage для файла Contact.cshtml:

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>

Обратите внимание, что URL-адрес, созданный для ссылки Contact на отображенной странице, отражает обновленный маршрут:

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 по ее обычному маршруту /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, использует соглашения, создающие точки расширения для настройки моделей страниц. Эти соглашения полезны при создании и изменении для обнаружения и обработки страниц.

В примерах этого раздела образец приложения использует класс AddHeaderAttribute, который является ResultFilterAttribute и применяет заголовок ответа:

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

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

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

Образец показывает использование соглашений для применения атрибута ко всем страницам в папке и к одной странице.

Соглашение для модели приложений папки

Используйте метод AddFolderApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в экземплярах PageApplicationModel для всех страниц в указанной папке.

Пример демонстрирует использование AddFolderApplicationModelConvention путем добавления заголовка OtherPagesHeader к страницам в папке OtherPages приложения:

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

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1 из примера и посмотрите заголовки, чтобы проверить результат:

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

Соглашение для модели приложений страницы

Используйте метод AddPageApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в классе PageApplicationModel для страницы с указанным именем.

Пример демонстрирует использование AddPageApplicationModelConvention путем добавления заголовка AboutHeader на страницу About:

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

Запросите страницу About по адресу 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();
});

Модель приложений страницы используется для проверки относительного пути на наличие сегментов, ведущих к странице Page2 в папке OtherPages. Если условие выполняется, добавляется заголовок. Если нет, применяется EmptyFilter.

EmptyFilter является фильтром действий. Так как в Razor Pages фильтры действий не учитываются, EmptyFilter не оказывает действия, как и задумано, если путь не содержит OtherPages/Page2.

Запросите страницу Page2 по адресу localhost:5000/OtherPages/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;
        }
    }
}

Запросите страницу About по адресу localhost:5000/About из примера и посмотрите заголовки, чтобы проверить результат:

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

Фильтры MVC и фильтр страниц (IPageFilter)

Фильтры действий MVC игнорируются в Razor Pages, так как 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 добавляются и настраиваются с помощью метода расширения AddRazorPagesOptions в AddMvc в коллекции служб в классе Startup. Следующие примеры соглашений описаны далее в этом разделе:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.Add( ... );
            options.Conventions.AddFolderRouteModelConvention(
                "/OtherPages", model => { ... });
            options.Conventions.AddPageRouteModelConvention(
                "/About", model => { ... });
            options.Conventions.AddPageRoute(
                "/Contact", "TheContactPage/{text?}");
            options.Conventions.AddFolderApplicationModelConvention(
                "/OtherPages", model => { ... });
            options.Conventions.AddPageApplicationModelConvention(
                "/About", model => { ... });
            options.Conventions.ConfigureFilter(model => { ... });
            options.Conventions.ConfigureFilter( ... );
        });
}

Порядок маршрутов

Для маршрутов указывается свойство Order, определяющее порядок обработки (сопоставления маршрутов).

Порядок Поведение
-1 Маршрут обрабатывается до обработки других маршрутов.
0 Порядок не задан (значение по умолчанию). Если свойство Order не задано (Order = null), значение Order по умолчанию для маршрута равно 0 (нулю).
1, 2, … n Указывает порядок обработки маршрутов.

Маршруты обрабатываются в соответствии с соглашением.

  • Маршруты обрабатываются по порядку (–1, 0, 1, 2, …, n).
  • Если маршруты имеют одинаковые значения свойства Order, сначала сопоставляется наиболее конкретный маршрут, а затем более общие.
  • Если URL-адресу запроса соответствуют маршруты с одинаковым значением свойства Order и одинаковым количеством параметров, они обрабатываются в том порядке, в котором были добавлены в коллекцию PageConventionCollection.

По возможности старайтесь не использовать строго определенный порядок обработки маршрутов. Как правило, при маршрутизации правильный маршрут выбирается посредством сопоставления URL-адресов. Если для правильной маршрутизации запросов необходимо задать свойства Order маршрута, схема маршрутизации приложения, скорее всего, будет малопонятна клиентам и сложна в обслуживании. Старайтесь упростить схему маршрутизации приложения. В примере приложения требуется явно определенный порядок обработки маршрутов для демонстрации нескольких сценариев маршрутизации на основе одного приложения. Однако в рабочих приложениях следует избегать задания свойства Order для маршрутов.

Средства маршрутизации в Razor Pages и контроллере MVC имеют общую реализацию. Сведения о порядке маршрута в разделах MVC доступны в разделе "Маршрутизация для действий контроллера: упорядочивание маршрутов атрибутов".

Соглашения для моделей

Добавьте делегат для IPageConvention, чтобы добавить соглашения для модели, применяемые к Razor Pages.

Добавление соглашения для модели маршрутов ко всем страницам

Используйте свойство Conventions, чтобы создать и добавить IPageRouteModelConvention в коллекцию экземпляров IPageConvention, которые применяются при формировании модели маршрутов страниц.

В примере приложения шаблон маршрута {globalTemplate?} добавляется ко всем страницам приложения:

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

Свойству Order для AttributeRouteModel задано значение 1. Это обеспечивает описанное ниже поведение сопоставления маршрутов в примере приложения.

  • Шаблон маршрута для TheContactPage/{text?} добавляется далее в разделе. Маршрут страницы Contact по умолчанию имеет порядок null (Order = 0), поэтому он сопоставляется до шаблона маршрута {globalTemplate?}.
  • Шаблон маршрута {aboutTemplate?} добавляется далее в разделе. Шаблону {aboutTemplate?} задано свойство Order, равное 2. При запросе страницы About по адресу /About/RouteDataValue значение RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.
  • Шаблон маршрута {otherPagesTemplate?} добавляется далее в разделе. Шаблону {otherPagesTemplate?} задано свойство Order, равное 2. При запросе любой страницы в папке Pages/OtherPages с параметром маршрута (например, /OtherPages/Page1/RouteDataValue), RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["otherPagesTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Параметры Razor Pages, такие как добавление Conventions, добавляются при добавлении MVC в коллекцию служб в Startup.ConfigureServices. Пример см. в образце приложения.

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

Запросите страницу About по адресу 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 для задания заголовка ответа. Класс показан полностью в разделе Соглашения для действий модели страниц далее.

Пример приложения использует класс 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());

Запросите страницу About по адресу 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, чтобы создать и добавить интерфейс IPageRouteModelConvention, вызывающий действие в классе PageRouteModel для всех страниц в указанной папке.

Пример приложения использует AddFolderRouteModelConvention для добавления шаблона маршрута {otherPagesTemplate?} к страницам в папке OtherPages:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы в папке Pages/OtherPages со значением параметра маршрута (например, /OtherPages/Page1/RouteDataValue), RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["otherPagesTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue из примера и проверьте результат:

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

Свойству Order для AttributeRouteModel задано значение 2. Это гарантирует, что при указании одного значения маршрута приоритетно выбирается значение данных маршрута из шаблона {globalTemplate?}, которому ранее в разделе было присвоено значение 1. При запросе страницы About со значением параметра маршрута по адресу /About/RouteDataValue, RouteDataValue загружается в RouteData.Values["globalTemplate"] (Order = 1), а не в RouteData.Values["aboutTemplate"] (Order = 2). Это происходит из-за значения свойства Order.

По возможности не задавайте свойство Order, чтобы оно имело значение Order = 0. Предоставьте системе маршрутизации возможность выбирать правильный маршрут.

Запросите страницу About по адресу 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, чтобы настроить маршрут к странице по указанному пути страницы. Созданные ссылки на страницу будут использовать заданный вами маршрут. Для установления маршрута метод AddPageRoute использует AddPageRouteModelConvention.

Пример приложения создает маршрут к /TheContactPage для файла Contact.cshtml:

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>

Обратите внимание, что URL-адрес, созданный для ссылки Contact на отображенной странице, отражает обновленный маршрут:

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 по ее обычному маршруту /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, использует соглашения, создающие точки расширения для настройки моделей страниц. Эти соглашения полезны при создании и изменении для обнаружения и обработки страниц.

В примерах этого раздела образец приложения использует класс AddHeaderAttribute, который является ResultFilterAttribute и применяет заголовок ответа:

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

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

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

Образец показывает использование соглашений для применения атрибута ко всем страницам в папке и к одной странице.

Соглашение для модели приложений папки

Используйте метод AddFolderApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в экземплярах PageApplicationModel для всех страниц в указанной папке.

Пример демонстрирует использование AddFolderApplicationModelConvention путем добавления заголовка OtherPagesHeader к страницам в папке OtherPages приложения:

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

Запросите страницу Page1 по адресу localhost:5000/OtherPages/Page1 из примера и посмотрите заголовки, чтобы проверить результат:

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

Соглашение для модели приложений страницы

Используйте метод AddPageApplicationModelConvention, чтобы создать и добавить интерфейс IPageApplicationModelConvention, вызывающий действие в классе PageApplicationModel для страницы с указанным именем.

Пример демонстрирует использование AddPageApplicationModelConvention путем добавления заголовка AboutHeader на страницу About:

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

Запросите страницу About по адресу 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();
});

Модель приложений страницы используется для проверки относительного пути на наличие сегментов, ведущих к странице Page2 в папке OtherPages. Если условие выполняется, добавляется заголовок. Если нет, применяется EmptyFilter.

EmptyFilter является фильтром действий. Так как в Razor Pages фильтры действий не учитываются, EmptyFilter не оказывает действия, как и задумано, если путь не содержит OtherPages/Page2.

Запросите страницу Page2 по адресу localhost:5000/OtherPages/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;
        }
    }
}

Запросите страницу About по адресу localhost:5000/About из примера и посмотрите заголовки, чтобы проверить результат:

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

Фильтры MVC и фильтр страниц (IPageFilter)

Фильтры действий MVC игнорируются в Razor Pages, так как Razor Pages использует методы обработчиков. Доступны для использования другие типы фильтров MVC: фильтры авторизации, исключений, ресурсов и результатов. Дополнительные сведения см. в разделе Фильтры.

Фильтр страниц (IPageFilter) — это фильтр, применяемый к страницам Razor Pages. Дополнительные сведения см. в разделе Методы фильтрации для Razor Pages.

Дополнительные ресурсы