Фильтры могут принимать некоторые значения из вне. Для их приема мы можем определить в классе фильтра конструктор с соответствующими параметрами. Например:
public class SimpleResourceFilter : Attribute, IResourceFilter { int _id; string _token; public SimpleResourceFilter(int id, string token) { _id = id; _token = token; } public void OnResourceExecuted(ResourceExecutedContext context) { } public void OnResourceExecuting(ResourceExecutingContext context) { context.HttpContext.Response.Headers.Add("Id", _id.ToString()); context.HttpContext.Response.Headers.Add("Token", _token); } }
Здесь конструктор фильтра принимает два параметра. При применении фильтра мы можем передать значения для этих параметров:
public class HomeController : Controller { [SimpleResourceFilter(30, "8h6ell3o5wor5ld8")] public IActionResult Index() { return View(); } }
Если фильтр устанавливается глобально, то также при его установке необходимо передать ему нужные значения:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(options=> options.Filters.Add(new SimpleResourceFilter(22, "jkrgbjkjgjghddw")));
Как и любые классы в ASP.NET Core, фильтры также могут принимать зависимости, устанавливаемые при старте приложения. Однако, если фильтр применяется непосредственно к контроллеру или его методу, то установка зависимостей через встроенный механизм Dependency Injection не будет работать. Все потому, что при применении атрибутов все значения должны быть переданы напрямую в их конструктор. Чтобы обойти это ограничение, надо использовать один из классов ServiceFilterAttribute или TypeFilterAttribute.
Например, пусть класс фильтра получает зависимость ILoggerFactory, которая позволяет создать объект логгера для логгирования событий приложения:
using Microsoft.AspNetCore.Mvc.Filters; public class SimpleResourceFilter : Attribute, IResourceFilter { ILogger _logger; public SimpleResourceFilter(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger("SimpleResourceFilter"); } public void OnResourceExecuted(ResourceExecutedContext context) { _logger.LogInformation($"OnResourceExecuted - {DateTime.Now}"); } public void OnResourceExecuting(ResourceExecutingContext context) { _logger.LogInformation($"OnResourceExecuting - {DateTime.Now}"); } }
Класс TypeFilterAttribute создает объект фильтра с помощью фабрики
Microsoft.Extensions.DependencyInjection.ObjectFactory
, а с помощью механизма DI устанавливает все зависимости для создаваемого фильтра. Применение TypeFilterAttribute:
[TypeFilter(typeof(SimpleResourceFilter))] public class HomeController : Controller { public IActionResult Index() { return View(); } }
Класс ServiceFilterAttribute в отличие от TypeFilterAttribute извлекает экземпляр фильтра напрямую из DI. Для этого при применении ему передается тип фильтра:
[ServiceFilter(typeof(SimpleResourceFilter))] public class HomeController : Controller { public IActionResult Index() { return View(); } }
Но чтобы данный фильтр стал доступен, его надо зарегистрировать в приложении в качестве сервиса:
using MvcApp.Filters; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); builder.Services.AddScoped<SimpleResourceFilter>(); // добавление фильтра в качестве зависимости var app = builder.Build(); app.MapDefaultControllerRoute(); app.Run();