Содержание
Как и любые классы .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, чтобы передать в фильтр сервис.

