В ASP.NET Core MVC фильтры имеют три области действия:
Метод контроллера. Атрибут применяется к методу контроллера:
public class HomeController : Controller { [SimpleResourceFilter] public IActionResult Index() { return View(); } }
Область действия контроллер.
Атрибут применяется к классу контроллера:
[SimpleResourceFilter] public class HomeController : Controller { // содержимое контроллера }
Глобальная область действия, при которой фильтр применяется ко всем методам всех контроллеров приложения.
Для определения фильтра как глобального надо при подключении соответствующих сервисов MVC добавить фильтр в коллекцию фильтров. Подключение глобально для всех сервисов MVC:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddMvc(options => { options.Filters.Add(typeof(SimpleResourceFilter)); // подключение по типу // альтернативный вариант подключения options.Filters.Add(new SimpleResourceFilter()); // подключение по объекту options.Filters.Add<SimpleResourceFilter>(); // применение типизированного метода });
Установка отдельно для контроллеров и представлений:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(options => { options.Filters.Add(typeof(SimpleResourceFilter)); // подключение по типу options.Filters.Add(new SimpleResourceFilter()); // подключение по объекту options.Filters.Add<SimpleResourceFilter>(); });
Кроме того, следует отметить, что есть определенная очередность выполнения фильтров в зависимости от области действия:
Очередность | Область действия | Метод фильтра |
1 | Глобальная | On[Stage]Executing |
2 | Контроллер | On[Stage]Executing |
3 | Действие контроллера | On[Stage]Executing |
4 | Действие контроллера | On[Stage]Executed |
5 | Контроллер | On[Stage]Executed |
6 | Глобальная | On[Stage]Executed |
Например, создадим в проекте папку Filters и определим в ней три класса фильтров - GlobalResourceFilter, ControllerResourceFilter и ActionResourceFilter:
Класс GlobalResourceFilter будет выполнять роль глобального фильтра и будет иметь следующий код:
using Microsoft.AspNetCore.Mvc.Filters; namespace MvcApp.Filters { public class GlobalResourceFilter : Attribute, IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { Console.WriteLine("GlobalResourceFilter.OnResourceExecuting"); } public void OnResourceExecuted(ResourceExecutedContext context) { Console.WriteLine("GlobalResourceFilter.OnResourceExecuted"); } } }
Класс ControllerResourceFilter будет фильтром на уровне контроллера и будет иметь следующий код:
using Microsoft.AspNetCore.Mvc.Filters; namespace MvcApp.Filters { public class ControllerResourceFilter : Attribute, IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { Console.WriteLine("ControllerResourceFilter.OnResourceExecuting"); } public void OnResourceExecuted(ResourceExecutedContext context) { Console.WriteLine("ControllerResourceFilter.OnResourceExecuted"); } } }
Класс ActionResourceFilter будет выполнять роль фильтра на уровне отдельного действия контроллера и будет иметь следующий код:
using Microsoft.AspNetCore.Mvc.Filters; namespace MvcApp.Filters { public class ActionResourceFilter : Attribute, IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { Console.WriteLine("ActionResourceFilter.OnResourceExecuting"); } public void OnResourceExecuted(ResourceExecutedContext context) { Console.WriteLine("ActionResourceFilter.OnResourceExecuted"); } } }
Изменим файл Program.cs для подключения классаGlobalResourceFilter в качестве глобального фильтра:
using MvcApp.Filters; // пространство имен фильтров var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(options => options.Filters.Add<GlobalResourceFilter>()); var app = builder.Build(); app.MapDefaultControllerRoute(); app.Run();
И определим следующий контроллер HomeController:
using Microsoft.AspNetCore.Mvc; using MvcApp.Filters; // пространство имен фильтров namespace MvcApp.Controllers { [ControllerResourceFilter] public class HomeController : Controller { [ActionResourceFilter] public IActionResult Index() => View(); } }
И после запуска приложения на консоли мы сможем наблюдать очередность выполнения фильтров:
ASP.NET Core MVC позволяет переопределить порядок выполнения фильтров. Для этого фильтр должен реализовать интерфейс IOrderedFilter, который определяет свойство Order - это свойство устанавливает порядок выполнения фильтра - чем оно меньше, тем раньше будет выполняться фильтр. Посмотрим на примере. Изменим класс ControllerResourceFilter следующим образом:
using Microsoft.AspNetCore.Mvc.Filters; namespace MvcApp.Filters { public class ControllerResourceFilter : Attribute, IResourceFilter, IOrderedFilter { public ControllerResourceFilter(int order) => Order = order; public int Order { get; } public void OnResourceExecuting(ResourceExecutingContext context) { Console.WriteLine("ControllerResourceFilter.OnResourceExecuting"); } public void OnResourceExecuted(ResourceExecutedContext context) { Console.WriteLine("ControllerResourceFilter.OnResourceExecuted"); } } }
Теперь класс ControllerResourceFilter через конструктор устанавливает свойство Order.
И также изменим код контроллера:
using Microsoft.AspNetCore.Mvc; using MvcApp.Filters; // пространство имен фильтров namespace MvcApp.Controllers { [ControllerResourceFilter(int.MinValue)] public class HomeController : Controller { [ActionResourceFilter] public IActionResult Index() => View(); } }
Значение int.MinValue
, которое передается через конструктор класса ControllerResourceFilter свойству Order, фактически означает, что этот фильтр будет запускаться раньше всех. В чем мы можем
убедиться, запустив проект: