MVC/Unity - 如何将依赖注入到自定义FilterAttribute中?

7

我有一个自定义的HandleErrorAttribute,它扩展了FilterAttribute

我如何让Unity在注入控制器的依赖项的同时,注入这个属性的依赖项?

3个回答

2

好的,问题已经解决。

我主要使用了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),因为在该上下文中filter是只读的。


1

我也遇到了这个问题,现在已经有一个可行的解决方案。它与上面描述的解决方案类似,但有一些细微的差别,并且还添加了完整的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。

完成了以上所有工作后,我现在可以直接将依赖项注入到我的过滤器中。

非常感谢任何评论和想法。

谢谢 Mike


1

你有两个选项

第一个选项是编写自定义的ActionInvoker,这并没有听起来那么难。查看这篇博客文章。它专门涉及NInject,但Unity支持属性注入,因此您可以修改示例以使用Unity。

这是将你的IoC容器耦合在一起的选项,不建议使用。

public class MyFilter 
{ 
  IMyService MyService {get; set;}

  MyFilter() : MyFilter(MyUnityContainer.Resolve<IMyService>())
  { }

  MyFilter(IMyService service)
  {
    MyService = service;
  }
}

我尝试了博客文章中提供的解决方案,但是Unity和Ninject之间似乎存在一些差异,或者在某个地方,有人的代码是错误的 :).当它们到达重写的“InvokeExceptionFilters”时,过滤器是只读的。因此,我可以声明一个新的过滤器并注入依赖项,但是如果我尝试在提供的ExceptionFilters列表上注入依赖项,则什么也不会发生。我可以创建一个新的过滤器并将其传递给基类,但是这样我将失去属性本身提供的所有声明性信息。 - Scott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接