Передача параметров в фильтры и установка зависимостей

Последнее обновление: 10.04.2022

Параметры фильтров

Фильтры могут принимать некоторые значения из вне. Для их приема мы можем определить в классе фильтра конструктор с соответствующими параметрами. Например:

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")));

Фильтры и Dependency Injection

Как и любые классы в 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();
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850