我正在尝试将依赖项注入自定义
AuthorizeAttribute
,如下所示:
public class UserCanAccessArea : AuthorizeAttribute
{
readonly IPermissionService permissionService;
public UserCanAccessArea() :
this(DependencyResolver.Current.GetService<IPermissionService>()) { }
public UserCanAccessArea(IPermissionService permissionService)
{
this.permissionService = permissionService;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
string AreaID =
httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;
bool isAuthorized = false;
if (base.AuthorizeCore(httpContext))
isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);
return isAuthorized;
}
}
这有效,但似乎是作为一个单例来解决的,这意味着我遇到了我的上一个问题
中描述的问题我想做的是使用属性注入,但由于我的属性本身没有被 Unity 解析,我无法找到一种方法来配置容器来拦截和解析属性。我尝试过以下方法:
public class UserCanAccessArea : AuthorizeAttribute
{
public IPermissionService permissionService { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
string AreaID =
httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;
bool isAuthorized = false;
if (base.AuthorizeCore(httpContext))
isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);
return isAuthorized;
}
}
容器:
container.RegisterType<UserCanAccessArea>(new InjectionProperty("permissionService"));
但该属性在运行时始终为空。
有人实现了这一点吗?如果是的话,你有一个例子吗?
您应该完全防止对属性进行依赖注入。本文解释了其原因:属性中的依赖注入:不要这样做!。文章总结道:
您有两个选择:
AuthorizeCore
)只执行从服务定位器/DependencyResolver 解析服务并调用服务的方法。这里需要注意的是,您不能进行构造函数注入、属性注入,并且服务不能存储在属性私有状态中(正如您已经注意到的那样)。使用哪个选项:
在 ASP.NET Core 中,现在可以通过创建自定义属性、实现 IFilterFactory,或使用 TypeFilterAttribute 以及 ServiceFilterAttribute。
两者都实现
IFilterFactory
并执行您通常在实现 IFilterFactory
的自定义属性中执行的操作,唯一的区别是它们支持排序(如果您愿意,可以在自定义属性中添加)。
但更具体地说 -
ServiceFilterAttribute
从实际服务集合中获取过滤器的实例,这允许您为其定义特定的生命周期,而 TypeFilterAttribute
不使用服务集合来创建对象,它使用 Microsoft .Extensions.DependencyInjection.ObjectFactory 这是 CreateFactory 方法的结果。 (基本上,它使用大量表达式树创建对象。) TypeFilterAttribute
还允许您传递非服务构造函数参数的参数。两者都使用任何 DI 的服务集合。
对于现有的代码库,您可以非常简单地执行以下任意操作来在属性的构造函数中实现依赖项注入:
[TypeFilter(typeof(MyExistingFilterWithConstructorDI))]
[TypeFilter(typeof(MyExistingFilterWithConstructorDIAndParams), Arguments = new object[] { "first non-service param", "second non-service param" })]
[ServiceFilter(typeof(MyExistingFilterWithConstructorDI))
(您需要将过滤器注册到具有适当生命周期的服务集合中)现在,就性能而言,如果您最终使用
TypeFilterAttribute
,将如上所述使用表达式树创建过滤器的类型,而如果您只是创建自己的 IFilterFactory
,则您可以控制该部分,即,您只需实例化您的对象,并且对于任何依赖项注入需求 - 您可以使用提供的 IServiceProvider
作为接口的 CreateInstance
方法的一部分。
IsReusable
属性作为 IFilterFactory
接口的一部分,可用于显示您是否更喜欢框架在请求范围之外使用您的对象。这决不能保证您的过滤器永远不会被单一对象所困扰。
我是这样实现的:
public class ClaimsHandlerAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var jwtAuthManager =
context.HttpContext.RequestServices.GetService(typeof(IJwtAuthManager))
as JwtAuthManager;
return;
}
}