我有一个派生自AuthorizationAttribute的自定义属性类,它对控制器操作执行自定义安全性。 OnAuthorizationCore方法依赖于各种其他组件(例如DAL),以判断用户是否可以调用操作。
我正在使用Autofac进行依赖注入。 ExtensibleActionInvoker声称能够在动作过滤器上执行属性注入。在运行时设置属性的属性(这似乎是一个坏主意)将在一个简单的单元测试中工作,但在繁忙的多线程Web服务器中它肯定会出错,所以这个想法似乎是一种反模式。因此这个问题:
如果我的AuthorizationAttribute依赖于其他组件才能正常工作,为了实现这一点,它的正确[架构]模式是什么?
即。 AuthorizationAttribute依赖于IUserRepository ...... 应该如何解决这种关系?
答案 0 :(得分:17)
ExtensibleActionInvoker声称能够在动作过滤器上执行属性注入。
正确 - 但不要将动作过滤器与可能无法实现它们的属性混淆。在ASP.NET MVC中处理此问题的最简单方法是分割职责,即使MVC框架允许您将它们组合在一起。
,例如,使用一对类 - 仅包含数据的属性类:
// Just a regular old attribute with data values
class SomeAttribute : Attribute { ... }
并且注入了依赖项的过滤器:
// Gets dependencies injected
class SomeFilter : IActionFilter { ... }
SomeFilter
只使用通过SomeAttribute
从控制器或操作方法获取GetCustomAttributes()
属性的典型方法来执行所需的任何工作。
然后,您可以使用ExtensibleActionInvoker
连接过滤器:
builder.RegisterControllers(...).InjectActionInvoker();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterType<SomeFilter>().As<IActionFilter>();
它可能比使用属性为过滤器的方法编写的代码多一点,但从长远来看,代码的质量会更好(例如,通过避免属性的限制和尴尬的服务定位器解决方案。)
答案 1 :(得分:2)
在MVC2之前没有直接的方法来做到这一点。这里有一个有趣的技术:http://www.mattlong.com.au/?p=154。我建议使用Common Service Locator对此进行抽象并找到您的DI容器。
如果您使用的是MVC 3,则可以使用MVC Service Location
答案 2 :(得分:2)
我认为实现这一目标的最简单方法是咬紧牙关并接受对autofac本身的依赖。虽然对IoC的依赖本身就是一种反模式,但它更适合。您可以按如下方式实现属性:
public class UserAuthorizeAttribute : AuthorizeAttribute
{
public IUserRepository CurrentUserService
{
get
{
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
return cp.RequestLifetime.Resolve<IUserRepository>();
}
}
}
...
答案 3 :(得分:0)
构造函数注入似乎不可能不改变过滤器注册的方式。
过去依赖注入困难的地方是过滤器属性本身。因为.NET框架运行时实际上负责创建这些属性实例,所以我们不能使用传统的依赖注入策略。
所以 - 下一个最好的东西是属性注入(Mvc3为开箱即用提供了一些支持)。
这是手动执行此操作的how to。
我个人使用MvcExtensions。我可以在different way注册它们。这是usage。
您可能想要调查的另一件事是MvcTurbine项目。与更为通用的MvcExtensions项目相反 - MvcTurbine主要用于提供依赖注入支持。