一、簡介
前幾篇文章都是講ASP.NET Core MVC中的依賴注入(DI)與擴展點的,也許大家都發現在ASP.NET CORE中所有的組件都是通過依賴注入來擴展的,而且面向一組功能就會有一組接口或抽象工廠來擴展功能,就如IControllerActivator這樣的功能點在上篇文章(查看.NET Core源代碼通過Autofac實現依賴注入到Controller屬性)中也提到了,今天我們主要介紹一個大類似的擴展點,ASP.NET Core MVC中為我們提供了新的機制為Action Filters(也就是過濾器)進行依賴注入的擴展。
二、過濾器依賴注入
在ASP.NET Core MVC中,框架中為我們提供了類型為 IFilter 的 Attributes 來裝飾Action,用於攔截Action請求,這有在以前的版本中就有了,但是如果我們想結合依賴注入使用的話要使用IFilterFactory接口來擴展Action Filter的創建過程。
2.1 IFilterFactory接口定義
public interface IFilterFactory : IFilter
{
IFilter CreateInstance([NotNull] IServiceProvider serviceProvider);
}
我們想要創建一個Filter Attribute並需要依賴注入的話一般想要的代碼為:
public class FilterClass : ActionFilterAttribute
{
public FilterClass(IDependency1 dependency1, IDependency2 dependency2)
{
// ...use dependencies
}
}
ASP.NET Core MVC中為我們提供了兩種簡單的IFilterFactory : ServiceFilterAttribute 和 TypeFilterAttribute 。來個例子看看怎么使用。
public class HomeController: Controller
{
[TypeFilter(typeof(FilterClass))]
[ServiceFilter(typeof(FilterClass))]
public IActionResult Index()
{
return View();
}
}
2.2 ServiceFilterAttribute
其實看到名字,有些朋友就能想到了,它是基於依賴注入的一個IFilterFactory,Service這個詞強化了它是一個通過獲取服務來實現依賴注入的,大家想到了什么?是不是GetService()? 沒錯,其實它的機制就是這個。
要使用ServiceFilter就必須在依賴注入容器里注冊對應的類型,比如下面的例子就要先將FilterClass類型注冊到IOC容器里。
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<FilterClass>();
services.AddMvc()
}
當然如果FilterClass類型的構造器需要注入類型時,也需要在IOC容器里進行注冊才可以使用。
我們來看下ServiceFilterAttribute的源代碼:
public class ServiceFilterAttribute : Attribute, IFilterFactory, IOrderedFilter
{
public ServiceFilterAttribute([NotNull] Type type)
{
ServiceType = type;
}
public Type ServiceType { get; private set; }
public int Order { get; set; }
public IFilter CreateInstance([NotNull] IServiceProvider serviceProvider)
{
var service = serviceProvider.GetRequiredService(ServiceType);
var filter = service as IFilter;
if (filter == null)
{
throw new InvalidOperationException(Resources.FormatFilterFactoryAttribute_TypeMustImplementIFilter(
typeof(ServiceFilterAttribute).Name,
typeof(IFilter).Name));
}
return filter;
}
}
2.3 TypeFilterAttribute
當然你也可以選擇使用這個類似於ServiceFilter過濾器的TypeFilter過濾器,它也同樣實現了IFilterFactory接口,並可以通過它創建出可使用依賴注入的過濾器來。之所以叫TypeFilter就是因為它並不需要在依賴注入容器里注冊類型就能創建出過濾器, 我們來看下它的代碼:
public class TypeFilterAttribute : Attribute, IFilterFactory, IOrderedFilter
{
private ObjectFactory factory;
public TypeFilterAttribute([NotNull] Type type)
{
ImplementationType = type;
}
public object[] Arguments { get; set; }
public Type ImplementationType { get; private set; }
public int Order { get; set; }
public IFilter CreateInstance([NotNull] IServiceProvider serviceProvider)
{
if (this.factory == null)
{
var argumentTypes = Arguments?.Select(a => a.GetType())?.ToArray();
this.factory = ActivatorUtilities.CreateFactory(ImplementationType, argumentTypes ?? Type.EmptyTypes);
}
return (IFilter)this.factory(serviceProvider, Arguments);
}
}
三、結語
相信看過上一篇文章的朋友都注意到了ServiceProvider和ActivatorUtilities 的不同,本文中的ServiceFilterAttribute和 TypeFilterAttribute 原理上也是通過它們來創建Filter的,所以使用場景就看大家如何來使用。其實最近看.NET Core的源代碼,看到的到處都是接口、工廠使用依賴注入形成擴展點的例子,其實微軟以前代碼的擴展點也挺多的,只是API並不那么開放,ASP.NET Core中我們看到了一個"開放"的框架。

