Фильтры RazorPages

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 11.12.2019

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

Фильтры Razor Pages срабатывают

  1. Когда уже выбран метод Razor Page для обработки запроса, но до привязки модели.

  2. После завершения привязки данных, но до выполнения метода Razor Page, который обрабатывает запрос

  3. После завершения методом обработки запроса.

    1. Фильтры Razor Pages могут применяться как к отдельным страницам RazorPages, так и глобально ко всем страницам.

      В плане функциональности фильтры представляют классы, которые реализуют либо интерфейс IPageFilter (синхроннная версия), либо интерфейс IAsyncPageFilter (асинхронная версия). Одновременно к стаице может применяться реализация только одного из этих интерфейсов. То есть можно применить либо синхронную, либо асинхронную версию, но не обе одновременно. Фреймворк ASP.NET Core вначале проверяет, применяются ли асинхронные фильтры - если они применяются, то именно они выполняются. Если асинхронные фильтры не применяются, то фреймворк ищет синхронные фильтры. Таким образом, если одновременно применяются и синхронные, и асинхронные фильтры, то выполяться будут только асинхронные фильтры.

      Интерфейс IPageFilter определяет следующие методы:

      • OnPageHandlerSelected: вызывается, когда выбран метод Razor Page для обработки запроса, но до выполнения привязки модели.

      • OnPageHandlerExecuting: вызывается после завершения привязки данных, но до выполнения метода Razor Page, который обрабатывает запрос.

      • OnPageHandlerExecuted: вызывается после завершения работы метода, но до выполнения результата метода.

      Интерфейс IAsyncPageFilter определяет следующие методы:

      • OnPageHandlerSelectionAsync: выполняется асинхронно, когда выбран метод Razor Page для обработки запроса, но до выполнения привязки модели.

      • OnPageHandlerExecutionAsync: выполняется асинхронно после завершения привязки данных, но до выполнения метода Razor Page, который обрабатывает запрос.

      Определение и применение синхронного фильтра

      Определим в проекте с RazorPages синхронный фильтр. Для реализации выберем примитивную задачу. Допустим, мы хотим запретить доступ пользователям с браузером Internet Explorer. Для этого определим следующий фильтр:

      using Microsoft.AspNetCore.Mvc;
      using Microsoft.AspNetCore.Mvc.Filters;
      using System;
      using System.Text.RegularExpressions;
      using Microsoft.Extensions.Logging;
      
      namespace RazorPagesApp.Filters
      {
          public class UserAgentPageFilter : Attribute, IPageFilter
          {
              public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
              {
                  
              }
      
              public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
              {
                  // получаем информацию о браузере пользователя
                  string userAgent = context.HttpContext.Request.Headers["User-Agent"].ToString();
                  if (Regex.IsMatch(userAgent, "MSIE|Trident"))
                  {
                      context.Result = new BadRequestObjectResult("Ваш браузер устарел");
                  }
              }
      
              public void OnPageHandlerSelected(PageHandlerSelectedContext context)
              {
                  
              }
          }
      }
      

      Функциональность синхронного фильтра определяется интерфейсом IPageFilter. В данном случае мы не только реализуем данный интерфейс, но и наследуем класс System.Attribute. Наследовать класс в прицнипе необязательно. В данном случае это сделано для того, чтобы потом можно было применить фильтр в качестве атрибута к классам отдельных страниц RazorPages.

      Поскольку нам надо проверять данные браузера до обработки запроса, то в данном случае мы можем использовать два метода: OnPageHandlerExecuting и OnPageHandlerSelected. В данном случае случае выбран метод OnPageHandlerExecuting(), который вызывается после привязки модели, но до обработки запроса страницей Razor Page. В качестве параметра он принимает объект PageHandlerExecutingContext, которые позволяет нам инспектировать данные запроса. Его основные свойства:

      • HandlerArguments: предоставляет информацию об аргументов, которые передаются в метод страницы RazorPage при обработке запроса.

      • HandlerInstance: возвращает экземпляр объекта, который содержит метод для обработки запроса. По сути содержит информацию о выбранной станице RazorPage

      • HandlerMethod: возвращает информацию о методе страницы Razor Page, который будет обрабатывать запрос

      • HttpContext: возвращает объект HttpContext, который содержит всю информацию о запросе и позволяет управлять ответом клиенту

      • ModelState: возвращает информацию о состоянии модели после выполнения привязки

      • Result: возвращает результат IActionResult, который представляет ответ клиенту

      • RouteData: возвращает данные маршрутов

      И в данном случае мы получаем через свойство HttpContext данные браузера клиента, с помощью регулярного выражения проверяем его, и если заголовок юзер-агента содержит соответствующие подстроки, то изменяем результат - теперь он представляет объект BadRequestObjectResult, с помощью которого пользователю отправляется статусный код 400 с некоторой информацией об ошибке.

      Метод OnPageHandlerSelected() вызывается до выполнения привязки модели (соответственно до метода OnPageHandlerExecuting), но после выбора обработчика Razor Page, который должен будет обрабатывать запрос. В качестве параметра он принимает объект PageHandlerSelectedContext, который инкапсулирует различную функциональность. Большая часть его свойств совпадает с выше рассмотренными свойствами PageHandlerExecutingContext.

      Метод OnPageHandlerExecuted() вызывается после обработки станицей Razor Page запроса. В данном методе мы можем при необходимости выполнить некоторую постобработку. В качестве параметра он принимает объект PageHandlerExecutedContext, свойства которого в основном совпадают с выше рассмотренными свойствами PageHandlerExecutingContext.

      Применение синхронного фильтра

      Вышеопределенный фильтр UserAgentPageFilter наследует класс Attribute, поэтому может применяться в качестве атрибута. Возьмем класс какой-нибудь страницы Razor Page, например, IndexModel, класс страницы Index.cshtml, который имеется в проекте по умолчанию в файле Index.cshtml.cs:

      Razor Pages Filters in ASP.NET Core

      Применим к нему фильтр:

      using Microsoft.AspNetCore.Mvc.RazorPages;
      using RazorPagesApp.Filters;
      
      namespace RazorPagesApp.Pages
      {
          [UserAgentPageFilter]
          public class IndexModel : PageModel
          {
              public void OnGet()
              {
      		
              }
          }
      }
      

      На странице Index.cshtml предусмотрим какое-нибудь содержимое, которое будет выводиться при обработке запроса:

      @page
      @model IndexModel
      @{
          ViewData["Title"] = "Home page";
      }
      
      <h2>Hello Razor Pages</h2>
      

      Обратимся к приложению из обычного браузера:

      Фильтры Razor Pages в ASP.NET Core

      А теперь обратимся к приложению из Internet Explorera:

      RazorPages Filters in ASP.NET Core MVC

      Определение и использование асинхронного фильтра

      Создадим аналогичный асинхронный фильтр:

      using Microsoft.AspNetCore.Http;
      using Microsoft.AspNetCore.Mvc.Filters;
      using System;
      using System.Text.RegularExpressions;
      using System.Threading.Tasks;
      
      namespace RazorPagesApp.Filters
      {
          public class UserAgentAsyncPageFilter : Attribute, IAsyncPageFilter
          {
              public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
              {
                  await Task.CompletedTask;
              }
      		
              public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
              {
                  string userAgent = context.HttpContext.Request.Headers["User-Agent"].ToString();
                  if (Regex.IsMatch(userAgent, "MSIE|Trident"))
                      context.Result = new BadRequestObjectResult("Ваш браузер устарел");
                  else
                      await next();  // передаем управление следующему фильтру или странице RazorPage при отсутствии других фильтров 
              }
          }
      }
      

      Асинхронный фильтр реализуется посредством применения интерфейса IAsyncPageFilter. Также, чтобы можно было применить фильтр в качестве атрибута, в данном случае также наследуем класс Attribute.

      Интерфейс IAsyncPageFilter определяет два метода. Сначала выполняется метод OnPageHandlerSelectionAsync(), который вызывается после определения обработчика страницы Razor Page, который будет обрабатывать запрос, но до привязки модели. В качестве параметра он принимает выше уже упоминавшийся объект PageHandlerSelectedContext, с помощью свойств которого мы можем инспектировать данные запроса. Но в данном случае опять же ничего не делаем, а просто возвращаем завершенную задачу.

      Метод OnPageHandlerExecutionAsync() вызывается после приязки модели, но до выполнения метода, и, таким образом, после вызова OnPageHandlerExecutionAsync. Он принимает два параметра. Первый параметр - объект PageHandlerExecutingContext уже выше рассматривался. С его помощью опять же можно получить всю многообразную информацию о запросе, какая страницы и какой ее метод выбран для обработки. А вот второй параметр - аргумент типа PageHandlerExecutionDelegate очень важен. Фактически он предоставляет делегат, вызов которого позволяет передать обработку запроса далее - либо следующим фильтрам (если они имеются), либо непосредственно самой странице Razor Page. И в данном случае мы вызываем данный делегат:

      await next();

      Если же мы этого не сделаем, то запрос до страницы не дойдет, даже если у пользователя нормальный браузер, а не Internet Explorer.

      Применение фильтра аналогично применению синхронной версии:

      [UserAgentAsyncPageFilter]
      public class IndexModel : PageModel
      {
      	public void OnGet()
      	{
      	
      	}
      }
      

      Соответственно мы получим те же самые результаты.

      Глобальная установка фильтра

      В примерах выше фильтр применялся только к отдельной странице Index.cshtml, но естественно мы можем задать его в качестве глобального и применять сразу ко всем страницам. Для этого изменим метод ConfigureServices() в классе Startup:

      public void ConfigureServices(IServiceCollection services)
      {
      	services.AddRazorPages()
      			.AddMvcOptions(options => options.Filters.Add(new UserAgentAsyncPageFilter()));
      	// или так
      	//services.AddMvc(options => options.Filters.Add(new UserAgentAsyncPageFilter()));
      }
      

      Соответственно после этого нам не надо применять фильтр в качестве атрибута к отдельным страницам RazorPages.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850