AuthenticationRequiredAttribute - класс
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();
}
}
ОШИБКА :
Error CS7036 There is no argument given that corresponds to the required formal parameter 'memoryCache' of 'AuthenticationRequiredAttribute.AuthenticationRequiredAttribute(IMemoryCache)' Project.Ground.WebUI
Моя проблема на самом деле: я не могу использовать инъекцию зависимостей в классах атрибутов.
Я хочу использовать этот атрибут без каких-либо параметров. Есть какое-то решение, чтобы решить эту проблему? Я использую внедрение зависимостей, но его нельзя использовать для атрибутов. Как я могу это использовать?
@Liam Этот вопрос касается ASP.NET MVC, а не ASP.NET Core, поэтому ответ здесь не применим.
Есть ли причина, по которой вы сегодня изменили принятый ответ? В моем ответе ниже выделены три распространенных подхода к этому, в то время как ответ спонсора фокусируется только на одном из них (который также часто считается антипаттерном).





Вместо разрешения при построении ActionExecutingContext.HttpContext.RequestServices должен предоставить вам ссылку на сервисный контейнер запроса во время запроса.
Так:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var svc = filterContext.HttpContext.RequestServices;
var memCache = svc.GetService<IMemoryCache>();
//..etc
using Microsoft.Extensions.DependencyInjection;
используя Memcache в фильтре действий и пытаясь получить значения, он всегда возвращает null
Согласно документация, у вас есть несколько вариантов:
If your filters have dependencies that you need to access from DI, there are several supported approaches. You can apply your filter to a class or action method using one of the following:
Если вы просто хотите, чтобы это работало быстро, вы можете просто использовать один из первых двух вариантов, чтобы применить фильтр к контроллеру или действию контроллера. При этом ваш фильтр не обязательно должен быть атрибутом:
[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>();
// …
}
}
Общий метод GetService <T> является методом расширения. Это означает, что вам необходимо: using Microsoft.Extensions.DependencyInjection;
Возможный дубликат Как использовать внедрение зависимостей с атрибутом?