В ASP.NET Core MVC фильтры могу иметь три различных области действия: метод контроллера, контроллер и глобальная область действия. Также, работа фильтров в конвейере осуществляется в строго очередности.
Области действия фильтров
Область действия фильтров — метод контроллера
Эту область действия мы использовали в предыдущей части следующим образом:
[UserCheckFilter]
public IActionResult Index(User user)
{
return View();
}
Область действия фильтров — контроллер
Указание этой области действия фильтра осуществляется аналогичным образом — с использованием фильтра, как атрибута. Например,
[UserCheckFilter]
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
....
В этом случае нет необходимости устанавливать фильтр для каждого метода по отдельности так как фильтр будет использоваться при выполнении каждого действия в контроллере.
Глобальная область действия фильтра
В этом случае фильтр будет применяться к каждому действию каждого контроллера приложения. Для того, чтобы фильтр действовал глобально, необходимо его зарегистрировать в коллекции фильтров при настройке приложения ASP.NET Core MVC. При этом, регистрировать фильтры можно несколькими способами:
Подключение фильтра глобально для всех сервисов MVC
builder.Services.AddMvc(options =>
{
options.Filters.Add(typeof(UserCheckFilter)); //подключение по типу фильтра
//ИЛИ ТАК:
options.Filters.Add(new UserCheckFilter());//передавая объект фильтра
options.Filters.Add<UserCheckFilter>();//применяя типизированный метод регистрации фильтра
});
во всех трех случаях мы регистрируем фильтр глобально для всех сервисов MVC. Также мы можем зарегистрировать фильтр глобально только для представлений и контроллеров приложения.
Подключение фильтра глобально для контроллеров и представлений
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(UserCheckFilter)); //подключение по типу фильтра
//ИЛИ ТАК:
options.Filters.Add(new UserCheckFilter());//передавая объект фильтра
options.Filters.Add<UserCheckFilter>();//применяя типизированный метод регистрации фильтра
});
В зависимости от того, какую область фильтра мы выбрали и от того, какие методы определены в фильтре, ASP.NET Core MVC определяет очередность выполнения фильтров.
Очередность выполнения фильтров
Очередность по умолчанию
По умолчанию, в ASP.NET Core MVC определена следующая очередность выполнения фильтров:
| Очередность | Область фильтра | Метод фильтра |
|---|---|---|
| 1 | Глобальный | OnActionExecuting |
| 2 | Контроллер | OnActionExecuting |
| 3 | Действие (метод) | OnActionExecuting |
| 4 | Действие (метод) | OnActionExecuted |
| 5 | Контроллер | OnActionExecuted |
| 6 | Глобальный | OnActionExecuted |
Чтобы продемонстрировать как работает очередь фильтров, создадим новое приложение ASP.NET Core MVC, добавим в него новую папку — Filters и создадим в ней три фильтра:
Код фильтров, для примера, сделаем максимально простым:
using Microsoft.AspNetCore.Mvc.Filters;
namespace AspFiltersSequence.Filters
{
public class MethodFilter : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("MethodFilter.OnActionExecuted");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("MethodFilter.OnActionExecuting");
}
}
}
using Microsoft.AspNetCore.Mvc.Filters;
namespace AspFiltersSequence.Filters
{
public class ControllerFilter : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("ControllerFilter.OnActionExecuted");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("ControllerFilter.OnActionExecuting");
}
}
}
using Microsoft.AspNetCore.Mvc.Filters;
namespace AspFiltersSequence.Filters
{
public class GlobalFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("GlobalFilter.OnActionExecuted");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("GlobalFilter.OnActionExecuting");
}
}
}
Теперь применим фильтр GlobalFilter глобально:
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(options=>options.Filters.Add<GlobalFilter>());
...
Фильтры MethodFilter и ControllerFilter применим в контроллере HomeController:
using AspFiltersSequence.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using AspFiltersSequence.Filters;
namespace AspFiltersSequence.Controllers
{
[ControllerFilter]
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[MethodFilter]
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
}
}
Теперь запустим приложение и увидим очередность выполнения фильтров в действии:
Так работает очередность фильтров по умолчанию. Однако, при необходимости, ASP.NET Core MVC позволяет переопределить порядок выполнения фильтров.
Переопределение очередности
Для того, чтобы переопределить очередность выполнения фильтра, он должен также реализовывать интерфейс IOrderedFilter. Этот интерфейс содержит свойство Order, которое устанавливает порядок выполнения фильтра — чем оно меньше, тем раньше будет выполняться фильтр. Например, сделаем так, чтобы фильтр для метода (MethodFilter) выполнялся раньше всех:
public class MethodFilter : Attribute, IActionFilter, IOrderedFilter
{
public int Order => -1;
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("MethodFilter.OnActionExecuted");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("MethodFilter.OnActionExecuting");
}
}
здесь мы установили фильтру свойство Order равное -1, что должно привести к тому, что в нашем приложении этот фильтр будет выполняться самым первым. Запустим приложение и посмотрим на результат:
Аналогичным образом, мы можем устанавливать очередность выполнения фильтров так, как нам это необходимо.
Итого
Фильтры в ASP.NET Core MVC могут иметь три области действия — метод контроллера, контроллер целом и глобальная область действия. В зависимости от области действия фильтра, по умолчанию ASP.NET Core MVC определяет очередность выполнения фильтра, которую можно переопределить, реализовав в классе фильтра интерфейс IOrderedFilter.
