Как я могу использовать внедрение зависимостей в .Net Core ActionFilterAttribute? - PullRequest
0 голосов
/ 09 октября 2018

AuthenticationRequiredAttribute Class

public class AuthenticationRequiredAttribute : ActionFilterAttribute
{
    ILoginTokenKeyApi _loginTokenKeyApi;
    IMemoryCache _memoryCache;

    public AuthenticationRequiredAttribute(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;

        _loginTokenKeyApi = new LoginTokenKeyController(new UnitOfWork());
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var memory = _memoryCache.Get(Constants.KEYNAME_FOR_AUTHENTICATED_PAGES);

        string requestedPath = filterContext.HttpContext.Request.Path;

        string tokenKey = filterContext.HttpContext.Session.GetString("TokenKey")?.ToString();

        bool? isLoggedIn = _loginTokenKeyApi.IsLoggedInByTokenKey(tokenKey).Data;

        if (isLoggedIn == null ||
            !((bool)isLoggedIn) ||
            !Constants.AUTHENTICATED_PAGES_FOR_NORMAL_USERS.Contains(requestedPath))
        {
            filterContext.Result = new JsonResult(new { HttpStatusCode.Unauthorized });
        }
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }
}

HomeController

public class HomeController : Controller
{
    IUserApi _userApi;
    ILoginTokenKeyApi _loginTokenKey;
    IMemoryCache _memoryCache;

    public HomeController(IUserApi userApi, ILoginTokenKeyApi loginTokenKey, IMemoryCache memoryCache)
    {
        _loginTokenKey = loginTokenKey;
        _userApi = userApi;

        _memoryCache = memoryCache;
    }

    [AuthenticationRequired] // There is AN ERROR !!
    public IActionResult Example()
    {
        return View();
    }
}

ОШИБКА:

Ошибка CS7036 Естьне приведен аргумент, который соответствует обязательному формальному параметру «memoryCache» в «AuthenticationRequiredAttribute.AuthenticationRequiredAttribute (IMemoryCache)» Project.Ground.WebUI

Моя проблема на самом деле: я не могу использовать внедрение зависимостейв классах атрибутов .

Я хочу использовать этот атрибут без каких-либо параметров.Есть ли решение, чтобы решить это?Я использую внедрение зависимости, но его нельзя использовать для атрибутов.Как я могу использовать это?

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Согласно документации , у вас есть несколько вариантов здесь:

Если ваши фильтры имеют зависимости, к которым вам нужен доступ из DI, есть несколько поддерживаемых подходов.Вы можете применить свой фильтр к классу или методу действия, используя одно из следующих действий:

Атрибуты ServiceFilter или TypeFilter

Если вы просто хотите, чтобы это работало быстроВы можете просто использовать одну из первых двух опций, чтобы применить свой фильтр к контроллеру или действию контроллера.При этом ваш фильтр не обязательно должен быть атрибутом:

[TypeFilter(typeof(ExampleActionFilter))]
public IActionResult Example()
    => View();

ExampleActionFilter может просто реализовать, например, IAsyncActionFilter, и вы можете напрямую зависеть от вещей, использующихВнедрение в конструктор:

public class ExampleActionFilter : IAsyncActionFilter
{
    private readonly IMemoryCache _memoryCache;
    public ExampleActionFilter(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    { … }
}

Вместо этого вы также можете использовать атрибут [ServiceFilter], чтобы получить тот же эффект, но тогда вам также потребуется зарегистрировать ваш ExampleActionFilter в контейнере для внедрения зависимостей в Startup.

Фабрика фильтров

Если вам нужна большая гибкость, вы можете создать собственную фабрику фильтров.Это позволяет вам написать заводской код для создания фактического экземпляра фильтра самостоятельно.Возможная реализация описанного выше ExampleActionFilter может выглядеть следующим образом:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ExampleActionFilterAttribute : Attribute, IFilterFactory
{
    public bool IsReusable => false;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return serviceProvider.GetService<ExampleActionFilter>();
    }
}

Затем вы можете использовать этот атрибут [ExampleActionFilter], чтобы инфраструктура MVC создала для вас экземпляр ExampleActionFilter, используяКонтейнер DI.

Обратите внимание, что эта реализация в основном то же, что и ServiceFilterAttribute.Просто его реализация позволяет избежать необходимости использовать ServiceFilterAttribute напрямую и позволяет вам иметь собственный атрибут.

Использование сервисного локатора

Наконец, есть еще один быстрый вариант, который позволяет вамполностью избегайте инъекций в конструктор.При этом используется шаблон поиска служб для динамического разрешения служб, когда ваш фильтр действительно работает.Поэтому вместо введения зависимости и ее непосредственного использования вы извлекаете ее явно из контекста:

public class ExampleActionFilter : ActionFilterAttribute
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var memoryCache = context.HttpContext.RequestServices.GetService<IMemoryCache>();

        // …
    }
}
0 голосов
/ 09 октября 2018

Вместо разрешения при построении, ActionExecutingContext.HttpContext.RequestServices должен дать вам ссылку на контейнер службы запроса на момент запроса.

Итак:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var svc = filterContext.HttpContext.RequestServices;
    var memCache = svc.GetService<IMemoryCache>();
    //..etc
...