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

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

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

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

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

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();
    }
}

Если фильтр устанавливается глобально, то также при его установке необходимо передать ему нужные значения:

public void ConfigureServices(IServiceCollection services)
{
	services.AddControllersWithViews()
			.AddMvcOptions(options=> options.Filters.Add(new SimpleResourceFilter(22, "jkrgbjkjgjghddw")));
}

Фильтры и Dependency Injection

Как и любые классы в ASP.NET Core, фильтры также могут принимать зависимости, устанавливаемые при старте приложения. Однако, если фильтр применяется непосредственно к контроллеру или его методу, то установка зависимостей через встроенный механизм Dependency Injection не будет работать. Все потому, что при применении атрибутов все значения должны быть переданы напрямую в их конструктор. Чтобы обойти это ограничение, надо использовать один из классов ServiceFilterAttribute или TypeFilterAttribute.

Например, пусть класс фильтра получает зависимость ILoggerFactory, которая позволяет создать объект логгера для логгирования событий приложения:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System;

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

Класс ServiceFilterAttribute извлекает экземпляр фильтра напрямую из DI. Для этого при применении ему передается тип фильтра:

[ServiceFilter(typeof(SimpleResourceFilter))]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

Но чтобы данный фильтр стал доступен, его еще надо зарегистрировать в методе ConfigureServices() класса Startup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddScoped<SimpleResourceFilter>();
}

Класс TypeFilterAttribute создает объект фильтра с помощью фабрики Microsoft.Extensions.DependencyInjection.ObjectFactory, а с помощью механизма DI устанавливает все зависимости для создаваемого фильтра. В этом случае класс фильтра больше не надо регистрировать в ConfigureServices().

Применение TypeFilterAttribute аналогично ServiceFilterAttribute:

[TypeFilter(typeof(SimpleResourceFilter))]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850