我的目标:在一个由DI提供的情况下注入一个IFilterProvider,但默认情况下回退到全局的FilterProviders.Providers.GetFilters()方法。
互联网上有很多资源(包括官方"微软的资源),它们演示了如何将IFilterProvider接口注入到类中。但是,所有这些都使用服务定位器反模式(按照Mark Seeman)来实现。这是我找到的列表:
那么这些方法有什么问题?他们都将DI容器注入目标类而不是相反。如果你在类中看到像container.Resolve()这样的东西,那么你就不会控制对象到DI容器的生命周期,这就是控制反转的真正含义。
此外,尝试创建全局FilterProviders.Providers实例的回退的问题是,虽然它与IFilterProvider接口具有相同的签名,但它实际上并不实现此接口。那么如何将全局静态成员注入逻辑默认值并仍允许使用DI来覆盖它呢?
答案 0 :(得分:2)
创建一个基于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>()
);
最重要的是,这种模式中没有任何服务定位器。