【发布时间】:2010-11-05 08:33:44
【问题描述】:
我有一个扩展 FilterAttribute 的自定义 HandleErrorAttribute。
如何让 Unity 在注入控制器依赖项的同时将依赖项注入此属性?
【问题讨论】:
标签: asp.net-mvc unity-container filterattribute
我有一个扩展 FilterAttribute 的自定义 HandleErrorAttribute。
如何让 Unity 在注入控制器依赖项的同时将依赖项注入此属性?
【问题讨论】:
标签: asp.net-mvc unity-container filterattribute
我也遇到了这个问题,现在有一个可行的解决方案。它类似于上面描述的解决方案,但有一些细微差别,并且还添加了完整的 Unity 代码。
首先,出于上述原因,我将使用属性注入,并且如上所述,我将使用 Unity 上的 BuildUp 方法将属性注入到已创建的过滤器中。
为此,我将所有控制器都继承自一个新的自定义基类。在那个基类上,我重写了 CreateActionInvoker 方法,以便设置我自己的自定义 ActionInvoker。
Protected Overrides Function CreateActionInvoker() As System.Web.Mvc.IActionInvoker
Return CustomActionInvoker
End Function
然后在我的 CustomActionInvoker 中覆盖 GetFilters 方法。
Protected Overrides Function GetFilters(ByVal controllerContext As ControllerContext, ByVal actionDescriptor As ActionDescriptor) As FilterInfo
Dim info = MyBase.GetFilters(controllerContext, actionDescriptor)
For Each MyAuthorizationFilter In info.AuthorizationFilters
MvcApplication.Container.BuildUp(MyAuthorizationFilter.GetType, MyAuthorizationFilter)
Next
For Each MyActionFilter In info.ActionFilters
MvcApplication.Container.BuildUp(MyActionFilter.GetType, MyActionFilter)
Next
For Each MyResultFilter In info.ResultFilters
MvcApplication.Container.BuildUp(MyResultFilter.GetType, MyResultFilter)
Next
For Each MyExceptionFilter In info.ExceptionFilters
MvcApplication.Container.BuildUp(MyExceptionFilter.GetType, MyExceptionFilter)
Next
Return info
End Function
与上面所说的相反,我没有发现在 For Each 循环中进行构建会导致任何问题。我还克服了原来的问题,即只通过接口引用对象,方法是使用 BuildUp 方法的其他重载之一,该方法采用 System.Type 以及现有对象。
完成以上所有操作后,我现在可以将依赖项直接注入到我的过滤器中。
非常感谢任何 cmets 和想法。
迈克干杯
【讨论】:
好的,想通了。
我主要使用了 Ben 在他所指的博文中的上述解决方案。
问题是 Unity 的行为有点不同。
您不能直接在过滤器上注入依赖项,因为它们分别属于 IActionFilter 和 IExceptionFilter 类型。这让我相信它们是只读的,但事实并非如此。只是 Unity 需要知道显式类型才能注入。
因此,在文章提供的覆盖方法中,Unity 用户需要查询过滤器的相关类型,然后构建它们。
public UnityActionInvoker(IUnityContainer container, IList<Type> typesToInject)
{
_container = container;
_typesToInject = typesToInject;
}
然后在被覆盖的方法中,执行如下操作:
var needsInjection = filters.Where(filter => typesToInject.Contains(filter.GetType()));
有点乱,但只需要完成一次,并且按照 Ben 的建议保持一切解耦。
另一个问题是您不能在 foreach 循环中调用 _container.BuildUp(filter),因为过滤器在该上下文中是只读的。
【讨论】:
你有两个选择
第一个选项是编写一个自定义的 ActionInvoker,这并不像听起来那么难。看看这个blog post。它专门处理 NInject,但 Unity 支持属性注入,因此您可以修改示例以使用 Unity。
这是与您的 IoC 容器耦合的选项,不推荐使用。
public class MyFilter
{
IMyService MyService {get; set;}
MyFilter() : MyFilter(MyUnityContainer.Resolve<IMyService>())
{ }
MyFilter(IMyService service)
{
MyService = service;
}
}
【讨论】: