Содержание
Как и любые классы .NET, фильтры могут принимать различное количество параметров, которые могут использоваться в работе фильтра. Кроме этого, в фильтры могут передаваться различные зависимости, необходимые для работы фильтра.
Передача параметров в фильтр
Чтобы передать какие-либо параметры в фильтр, необходимо создать конструктор класса фильтра с параметрами. Например,
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace AspFilterParameters.Filters { public class TokenActionFilter : Attribute, IActionFilter { private readonly string _token; public TokenActionFilter(string token) { _token = token; } public void OnActionExecuted(ActionExecutedContext context) { } public void OnActionExecuting(ActionExecutingContext context) { if ((_token == null) || (_token != "12345")) { context.Result = new UnauthorizedResult(); } } } }
Здесь в параметрах конструктора класса TokenActionFilter
передается некий токен, значение которого, в дальнейшем, проверяется в методе OnActionExecuting()
и, в зависимости от проверки, выдается результат UnauthorizedResult
с кдом статуса 401. Применим этот фильтр, например, к методу контроллера HomeController
:
using AspFilterParameters.Models; using Microsoft.AspNetCore.Mvc; using AspFilterParameters.Filters; namespace AspFilterParameters.Controllers { public class HomeController : Controller { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } public IActionResult Index() { return View(); } [TokenActionFilter(token:"45678")] public IActionResult Privacy() { return View(); } } }
Теперь запустим приложение и попробуем перейти на страницу Privacy:
Если изменить значение параметра фильтра так:
[TokenActionFilter(token:"12345")] public IActionResult Privacy() { return View(); }
то мы свободно перейдем на страницу:
Если мы устанавливаем фильтр глобально, то также должны передать все параметры фильтра
builder.Services.AddControllersWithViews(options=>options.Filters.Add(new TokenActionFilter("12345")));
Передача зависимостей в фильтры
При передаче в фильтр зависимостей в ASP.NET Core MVC имеется небольшой нюанс. Например, создадим следующий фильтр:
using Microsoft.AspNetCore.Mvc.Filters; namespace AspFilterParameters.Filters { public class LogResourceFilter : Attribute, IResourceFilter { ILogger logger; public LogResourceFilter(ILoggerFactory factory) { logger = factory.CreateLogger("LogResourceFilter"); } public void OnResourceExecuted(ResourceExecutedContext context) { logger.LogInformation("OnResourceExecuted"); } public void OnResourceExecuting(ResourceExecutingContext context) { logger.LogInformation("OnResourceExecuting"); } } }
Теперь попробуем применить этот фильтр к контроллеру (или методу):
[LogResourceFilter] public class HomeController : Controller
Мы получим ошибку следующего содержания:
При применении атрибутов все значения должны быть переданы напрямую в их конструктор. При этом, если мы используем глобальную область действия фильтра, то проблем не возникнет:
builder.Services.AddControllersWithViews(options=>options.Filters.Add<LogResourceFilter>());
Чтобы решить проблему с фильтрами для методов или контроллеров мы должны воспользоваться одним из атрибутов: ServiceFilterAttribute
или TypeFilterAttribute
.
ServiceFilterAttribute
Этот атрибут напрямую извлекает экземпляр фильтра из контейнера DI. Чтобы воспользоваться этим атрибутом, в параметрах атрибута необходимо передать тип фильтра, а сам фильтр зарегистрировать в качестве сервиса, например:
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddTransient<LogResourceFilter>();//регистрируем фильтр как сервис ///другой код метода Main
[ServiceFilter(typeof(LogResourceFilter))] public class HomeController : Controller { //код контроллера }
Теперь фильтр будет работать:
TypeFilterAttribute
Класс TypeFilterAttribute
создает объект фильтра с помощью фабрики Microsoft.Extensions.DependencyInjection.ObjectFactory
, а с помощью механизма DI устанавливает все зависимости для создаваемого фильтра:
[TypeFilter(typeof(LogResourceFilter))] public class HomeController : Controller { //код контроллера }
при этом, TypeFilterAttribute
не требует, чтобы фильтр был зарегистрирован как сервис.
Итого
При необходимости, мы можем передавать в фильтры различные параметры и зависимости. Чтобы передать в фильтр параметры или зависимости, необходимо определить конструктор фильтра с необходимыми параметрами. Все параметры фильтра должны быть определены в конструкторе, поэтому, для передачи в фильтр сервисов мы должны использовать дополнительные атрибуты TypeFilterAttribute
или ServiceFilterAttribute
, чтобы передать в фильтр сервис.