c# - 没有服务定位器的 IFilterProvider 注入(inject)

标签 c# asp.net-mvc asp.net-mvc-4 dependency-injection asp.net-mvc-filters

我的目标:在 DI 提供 IFilterProvider 的情况下注入(inject) IFilterProvider,但默认情况下回退到全局 FilterProviders.Providers.GetFilters() 方法。

Internet 上有很多资源(包括“官方”Microsoft 资源)演示如何将 IFilterProvider 接口(interface)注入(inject)到类中。然而,它们都使用服务定位器反模式(根据 Mark Seeman)来做到这一点。以下是我找到的列表:

  1. http://msdn.microsoft.com/en-us/vs2010trainingcourse_aspnetmvcdependencyinjection_topic4.aspx
  2. http://merbla.blogspot.com/2011/02/ifilterprovider-using-autofac-for-mvc-3.html
  3. http://thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in-asp-net-mvc-3
  4. IFilterProvider and separation of concerns

那么这些方法有什么问题呢?它们都将 DI 容器注入(inject)到目标类中,而不是相反。如果您在类中看到像container.Resolve()这样的东西,那么您并没有将对象生命周期的控制权交给DI容器,这就是控制反转的真正含义。

此外,尝试创建全局 FilterProviders.Providers 实例的回退的问题是,尽管它具有与 IFilterProvider 接口(interface)相同的签名,但它实际上并未实现此接口(interface)。那么如何将全局静态成员作为逻辑默认值注入(inject)并仍然允许使用 DI 覆盖它呢?

最佳答案

基于 IFilterProvider 创建一个包装类,返回全局 FilterProviders.Providers.GetFilters() 结果,如下所示:

public class FilterProvider
    : IFilterProvider
{
    #region IFilterProvider Members

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        return FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor);
    }

    #endregion
}

然后,调整需要依赖项的类中的构造函数。

public class MyBusinessClass
    : IMyBusinessClass
{
    public MyBusinessClass(
        IFilterProvider filterProvider
        )
    {
        if (filterProvider == null)
            throw new ArgumentNullException("filterProvider");
        this.filterProvider = filterProvider;
    }
    protected readonly IFilterProvider filterProvider;

    public IEnumerable<AuthorizeAttribute> GetAuthorizeAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = filterProvider.GetFilters(controllerContext, actionDescriptor);

        return filters
                .Where(f => typeof(AuthorizeAttribute).IsAssignableFrom(f.Instance.GetType()))
                .Select(f => f.Instance as AuthorizeAttribute);
    }
}

接下来,配置您的 DI 容器以使用 FilterProvider 具体类型作为默认值。

container.Configure(x => x
    .For<IFilterProvider>()
    .Use<FilterProvider>()
);

如果您需要覆盖默认值并提供自己的 IFilterProvider,现在只需基于 IFilterProvider 创建一个新的具体类型并交换 DI 容器中注册的内容即可。

//container.Configure(x => x
//    .For<IFilterProvider>()
//    .Use<FilterProvider>()
//);

container.Configure(x => x
    .For<IFilterProvider>()
    .Use<NewFilterProvider>()
);

最重要的是,此模式中的任何位置都没有服务定位器。

关于c# - 没有服务定位器的 IFilterProvider 注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15048030/

相关文章:

c# - 如何在 visual studio 2010 中添加 System.Windows.Forms

c# - outlook 2010 addin c#:::自定义表单在客户端计算机上不起作用

c# - 在 WCF 服务 channel 调度程序上安装 IErrorHandler

c# - User.config 是如何创建的以及如何使用

asp.net-mvc - MVC 模型状态

regex - MVC4 中的正则表达式

asp.net-mvc-4 - MVC4 StyleBundle 没有以正确的顺序呈现包

asp.net - 在 ASP.NET MVC 后的 ajax 中包含 antiforgerytoken

c# - 每个 ID 删除许多记录 - MVC C#

asp.net-mvc - 当我们在 Visual Studio 中进行 FTP 发布时,将为 Controller 创建哪个 dll