ASP.NET Core Filter与IOC的羁绊
前言
????我們在使用ASP.NET Core進(jìn)行服務(wù)端應(yīng)用開發(fā)的時候,或多或少都會涉及到使用Filter的場景。Filter簡單來說是Action的攔截器,它可以在Action執(zhí)行之前或者之后對請求信息進(jìn)行處理。我們知道.Net Core默認(rèn)是提供了IOC的功能,而且IOC是.Net Core的核心,.Net Core的底層基本上是基于IOC構(gòu)建起來的,但是默認(rèn)情況下自帶的IOC不支持屬性注入功能,但是我們在定義或使用Filter的時候有時候不得不針對某個Controller或Action,這種情況下我們不得不將Filter作為Attribute標(biāo)記到Controller或Action上面,但是有時候Filter是需要通過構(gòu)造函數(shù)注入依賴關(guān)系的,這個時候就有了一點小小的沖突,就是我們不得不解決在Controller或Action上使用Filter的時候,想辦法去構(gòu)建Filter的實例。本篇文章不是一篇講解ASP.NET Core如何使用過濾器Filter的文章,而是探究一下Filter與IOC的奇妙關(guān)系的。
簡單示例
????咱們上面說過了,我們所用的過濾器即Filter,無論如何都是需要去解決與IOC的關(guān)系的,特別是在當(dāng)Filter作用到某些具體的Controller或Action上的時候。因為直接標(biāo)記的話必須要給構(gòu)造函數(shù)傳遞初始化參數(shù),但是這些參數(shù)是需要通過DI注入進(jìn)去的,而不是手動傳遞。微軟給我們提供了解決方案來解決這個問題,那就是使用TypeFilterAttribute或ServiceFilterAttribute,關(guān)于這兩個Attribute使用的方式,咱們先通過簡單的示例演示一下。首先定義一個Filter,模擬一下需要注入的場景
public class MySampleActionFilter : Attribute, IActionFilter {private readonly IPersonService _personService;private readonly ILogger<MySampleActionFilter> _logger;//模擬需要注入一些依賴關(guān)系public MySampleActionFilter(IPersonService personService, ILogger<MySampleActionFilter> logger){_personService = personService;_logger = logger;_logger.LogInformation($"MySampleActionFilter.Ctor {DateTime.Now:yyyyMMddHHmmssffff}");}public void OnActionExecuted(ActionExecutedContext context){Person personService = _personService.GetPerson(1);_logger.LogInformation($"TraceId=[{context.HttpContext.TraceIdentifier}] MySampleActionFilter.OnActionExecuted ");}public void OnActionExecuting(ActionExecutingContext context){_logger.LogInformation($"TraceId=[{context.HttpContext.TraceIdentifier}] MySampleActionFilter.OnActionExecuting ");} }這里的日志功能ILogger在ASP.Net Core底層已經(jīng)默認(rèn)注入了,我們還模擬依賴了一些業(yè)務(wù)的場景,因此我們需要注入一些業(yè)務(wù)依賴,比如我們這里的PersonService。
public void ConfigureServices(IServiceCollection services) {//模擬注冊一下業(yè)務(wù)依賴services.AddScoped<IPersonService,PersonService>();services.AddControllers(); }單獨使用Filter
這里我們先來演示一下單獨在某些Controller或Action上使用Filter的情況,我們先來定義一個Action來模擬一下Filter的使用,由于Filter通過構(gòu)造函數(shù)依賴了一下具體的服務(wù)所以我們先選擇使用TypeFilterAttribute來演示,具體使用方式如下
[Route("api/[controller]/[action]")] [ApiController] public class PersonController : ControllerBase {private readonly List<Person> _persons;public PersonController(){//模擬一下數(shù)據(jù)_persons = new List<Person>{new Person{ Id=1,Name="張三" },new Person{ Id=2,Name="李四" },new Person{ Id=3,Name="王五" }};}[HttpGet]//這里我們先通過TypeFilter的方式來使用定義的MySampleActionFilter[TypeFilter(typeof(MySampleActionFilter))]public List<Person> GetPersons(){return _persons;} }然后我們運行起來示例,模擬請求一下GetPersons這個Action看一下效果,因為我們在定義的Filter中記錄了日志信息,因此請求完成之后在控制臺會打印出如下信息
info: Web5Test.MySampleActionFilter[0]MySampleActionFilter.Ctor 202110121820482450 info: Web5Test.MySampleActionFilter[0]TraceId=[0HMCDD7ARPKDK:00000003] MySampleActionFilter.OnActionExecuting info: Web5Test.MySampleActionFilter[0]TraceId=[0HMCDD7ARPKDK:00000003] MySampleActionFilter.OnActionExecuted這個時候我們將TypeFilterAttribute替換為ServiceFilterAttribute來看一下效果,替換后的Action是這個樣子的
[HttpGet] [ServiceFilter(typeof(MySampleActionFilter))] public List<Person> GetPersons() {return _persons; }然后我們再來請求一下GetPersons這個Action,這個時候我們發(fā)現(xiàn)拋出了一個InvalidOperationException的異常,異常信息大致如下
System.InvalidOperationException: No service for type 'Web5Test.MySampleActionFilter' has been registered.從這個異常信息我們可以看出我們自定義的MySampleActionFilter過濾器需要注冊到IOC中去,所以我們需要注冊一下
public void ConfigureServices(IServiceCollection services) {//模擬注冊一下業(yè)務(wù)依賴services.AddScoped<IPersonService,PersonService>();//注冊自定義的MySampleActionFilterservices.AddScoped<MySampleActionFilter>();services.AddControllers(); }做了如上的修改之后,我們再次啟動項目請求一下GetPersons這個Action,這個時候MySampleActionFilter可以正常工作了。
這里簡單的說明一下關(guān)于需要注冊Filter的生命周期時,如果你不知道該注冊成哪種生命周期的話那就注冊成成Scope,這個是一種比較合理的方式,也就是和Controller生命周期保持一致每次請求創(chuàng)建一個實例即可。注冊成單例的話很多時候會因為使用不當(dāng)出現(xiàn)一些問題。
通過上面的演示我們大概了解了TypeFilterAttribute或ServiceFilterAttribute的使用方式和區(qū)別。
?使用TypeFilterAttribute的時候我們的Filter過濾器是不需要注冊到IOC中去的,因為它使用Microsoft.Extensions.DependencyInjection.ObjectFactory對Filte過濾器類型進(jìn)行實例化?使用ServiceFilterAttribute的時候我們需要提前將我們定義的Filter注冊到IOC容器中去,因為它使用容器來創(chuàng)建Filter的實例
全局注冊的場景
很多時候呢,我們是針對全局使用Filter對所有的或者絕大多數(shù)的Action請求進(jìn)行處理,這個時候我們會全局注冊Filter而不需要在每個Controller或Action上一一注解。這個時候也涉及到關(guān)于Filter本身是否需要注冊到IOC容器中的情況,這個地方需要注意的是Filter不是必須的需要托管到IOC容器當(dāng)中去,但是一旦托管到IOC容器當(dāng)中就需要注意不同注冊Filter的方式,首先我們來看一下不將Filter注冊到IOC的使用方式,還是那個示例
public void ConfigureServices(IServiceCollection services) {services.AddScoped<IPersonService,PersonService>();services.AddControllers(options => {options.Filters.Add<MySampleActionFilter>();}); }只需要把自定義的MySampleActionFilter依賴的服務(wù)提前注冊到IOC容器即可不需要多余的操作,這個時候MySampleActionFilter就可以正常的工作。還有一種方式就是你想讓IOC容器去托管自定義的Filter,這個時候我們需要將Filter注冊到容器中去,當(dāng)然聲明周期我們還是選擇Scope,這個時候我們需要注意一下注冊全局Filter的方式了,如下所示
public void ConfigureServices(IServiceCollection services) {services.AddScoped<IPersonService,PersonService>();services.AddScoped<MySampleActionFilter>();services.AddControllers(options => {//這里需要注意注冊Filter的方法應(yīng)使用AddServiceoptions.Filters.AddService<MySampleActionFilter>();}); }如上面代碼所示,為了能讓Filter的實例來自于IOC容器,在注冊全局Filter的時候我們應(yīng)使用AddService方法完成注冊,否則的話即使使用Add方法不會報錯但是在IOC中你只能注冊了個寂寞,總結(jié)一下全局注冊的時候
?如果你不想將全局注冊的Filter托管到IOC容器中,那么需要使用Add方法,這樣的話Filter實例則不會通過IOC容器創(chuàng)建?如果你想控制Filter實例的生命周期,則需要將Filter提前注冊到IOC容器中去,這個時候注冊全局Filter的時候就需要使用AddService方法,如果使用了AddService方法,但是你沒有在IOC中注冊Filter,則會拋出異常
源碼探究
上面我們已經(jīng)演示了將Filter托管到IOC容器和不使用IOC容器的使用方式,這方面微軟考慮的也是很周到,不過就是容易讓新手犯錯。如果能熟練掌握,或者理解其中的工作原理的話,還是可以更好的使用這些,并且微軟還為我們提供了一套靈活的擴(kuò)展方式。想要更好的了解它們的工作方式,我們還得在源碼下手。
TypeFilterAttribute
首先我們來看一下TypeFilterAttribute的源碼,我們知道在某個Action上使用TypeFilterAttribute的時候是不要求將Filter注冊到IOC中去的,因為這個時候Filter的實例是通過ObjectFactory創(chuàng)建出來的。在開始之前我們需要知道一個常識那就是在ASP.NET Core上我們所使用的Filter都必須要實現(xiàn)IFilterMetadata接口,這是ASP.NET Core底層知道Filter的唯一憑證,比如我們上面自定義的MySampleActionFilter是實現(xiàn)了IActionFilter接口,那么IActionFilter肯定是直接或間接的實現(xiàn)了IFilterMetadata接口,我們可以看一下IActionFilter接口的定義[點擊查看源碼👈[1]]
public interface IActionFilter : IFilterMetadata {void OnActionExecuting(ActionExecutingContext context);void OnActionExecuted(ActionExecutedContext context); }通過上面的代碼我們可以看到Filter本身肯定是要實現(xiàn)自IFilterMetadata接口的,這個是Filter的身份標(biāo)識。接下來我們就來看一下TypeFilterAttribute源碼的定義[點擊查看源碼👈[2]]
public class TypeFilterAttribute : Attribute, IFilterFactory, IOrderedFilter {//創(chuàng)建Filter實例的工廠private ObjectFactory? _factory;public TypeFilterAttribute(Type type){ImplementationType = type ?? throw new ArgumentNullException(nameof(type));}/// <summary>/// 創(chuàng)建Filter時需要的構(gòu)造參數(shù)/// </summary>public object[]? Arguments { get; set; }/// <summary>/// Filter實例的類型/// </summary>public Type ImplementationType { get; }/// <summary>/// Filter的優(yōu)先級順序/// </summary>public int Order { get; set; }/// <summary>/// 是否跨請求使用/// </summary>public bool IsReusable { get; set; }/// <summary>/// 創(chuàng)建Filter實例的實現(xiàn)方法/// </summary>public IFilterMetadata CreateInstance(IServiceProvider serviceProvider){if (serviceProvider == null){throw new ArgumentNullException(nameof(serviceProvider));}if (_factory == null){//獲取自定義傳遞的初始化Filter實例的參數(shù)類型以創(chuàng)建ObjectFactoryvar argumentTypes = Arguments?.Select(a => a.GetType())?.ToArray();//通過ActivatorUtilities創(chuàng)建ObjectFactory_factory = ActivatorUtilities.CreateFactory(ImplementationType, argumentTypes ?? Type.EmptyTypes);}//通過IServiceProvider實例和傳遞的初始換參數(shù)得到IFilterMetadata實例即Filter實例var filter = (IFilterMetadata)_factory(serviceProvider, Arguments);//可以是嵌套的IFilterFactory實例if (filter is IFilterFactory filterFactory){filter = filterFactory.CreateInstance(serviceProvider);}//返回創(chuàng)建的IFilterMetadata實例return filter;} }通過上面的代碼我們可以得知TypeFilterAttribute中包含一個CreateInstance方法,而這個方法正是創(chuàng)建返回了一個IFilterMetadata實例即Filter實例,而創(chuàng)建IFilterMetadata實例則是通過ActivatorUtilities這個類創(chuàng)建的。在之前的文章中我們曾大致提到過這個類,ActivatorUtilities類可以借助IServiceProvider來創(chuàng)建一個具體的對象實例,所以當(dāng)你不想使用DI的方式獲取一個類的實例,但是這個類的依賴需要通過IOC容器去獲得,那么可以借助ActivatorUtilities類來實現(xiàn)。需要注意的是雖然Filter實例是通過ActivatorUtilities創(chuàng)建出來的,而且它的依賴項來自IOC容器,但是FIlter實例本身并不受IOC容器托管。所以我們在使用的時候并沒有將Filter注冊到IOC容器中去。
ServiceFilterAttribute
上面我們看到了TypeFilterAttribute的實現(xiàn)方式,接下來我們來看一下和它類似的ServiceFilterAttribute的實現(xiàn)。我們知道ServiceFilterAttribute創(chuàng)建Filter實例必須要依賴IOC容器,即我們需要自行將Filter提前注冊到IOC容器中去,這樣才能通過ServiceFilterAttribute來正確的獲取到Filter的實例,接下來我們就來通過源碼來一探究竟[點擊查看源碼👈[3]]
public class ServiceFilterAttribute : Attribute, IFilterFactory, IOrderedFilter {/// <summary>/// 要實例化Filter的類型/// </summary>public ServiceFilterAttribute(Type type){ServiceType = type ?? throw new ArgumentNullException(nameof(type));}/// <summary>/// Filter執(zhí)行的優(yōu)先級順序/// </summary>public int Order { get; set; }/// <summary>/// 要實例化Filter的類型/// </summary>public Type ServiceType { get; }/// <summary>/// 是否跨請求使用/// </summary>public bool IsReusable { get; set; }/// <summary>/// 創(chuàng)建Filter實例的實現(xiàn)方法/// </summary>public IFilterMetadata CreateInstance(IServiceProvider serviceProvider){if (serviceProvider == null){throw new ArgumentNullException(nameof(serviceProvider));}//直接在IServiceProvider實例中獲取IFilterMetadata實例var filter = (IFilterMetadata)serviceProvider.GetRequiredService(ServiceType);//支持IFilterFactory自身的嵌套執(zhí)行if (filter is IFilterFactory filterFactory){filter = filterFactory.CreateInstance(serviceProvider);}return filter;} }通過上面的代碼我們可以看到ServiceFilterAttribute與TypeFilterAttribute的不同之處。首先ServiceFilterAttribute不支持手動傳遞初始化參數(shù),因為它初始化的依賴全部來自于IOC容器。其次IFilterMetadata實例本身也是直接在IOC容器中獲取的,而并不是僅僅只是依賴關(guān)系使用IOC容器。這也就是為何我們在使用ServiceFilterAttribute的時候需要自行先將Filter注冊到IOC容器中去。
IFilterFactory
我們上面看到了無論是ServiceFilterAttribute還是TypeFilterAttribute,它們都是實現(xiàn)了IFilterFactory接口,它們之所以可以定義創(chuàng)建Filter實例的實現(xiàn)方法也完全是實現(xiàn)了CreateInstance方法,所以本質(zhì)都是IFilterFactory。通過這個名字我們可以看出它是創(chuàng)建Filter的工廠,ServiceFilterAttribute和TypeFilterAttribute只是通過這個接口實現(xiàn)了自己創(chuàng)建IFilterFactory的邏輯。這是微軟給我們提供的一個靈活之處,通過它我們可以在請求管道的任意位置創(chuàng)建Filter實例。接下來我們就來看一下IFilterFactory的定義[點擊查看源碼👈[4]]
public interface IFilterFactory : IFilterMetadata {/// <summary>/// 是否跨請求使用/// </summary>bool IsReusable { get; }/// <summary>/// 創(chuàng)建Filter實例/// </summary>/// <param name="serviceProvider">IServiceProvider實例</param>/// <returns>返回Filter實例</returns>IFilterMetadata CreateInstance(IServiceProvider serviceProvider); }通過代碼可知IFilterFactory也是實現(xiàn)了IFilterMetadata接口,所以它本身也是一個Filter,只是它比較特殊一些。既然它是一個Filter,但是它也很特殊,那么ASP.NET Core在使用的時候是如何區(qū)分是一個Filter實例,還是一個IFilterFactory實例呢?這兩者存在一個本質(zhì)的區(qū)別,Filter實例是可以直接在Action請求的時候拿來執(zhí)行一些類似OnActionExecuting或OnActionExecuted的操作的,但是IFilterFactory實例需要先調(diào)用CreateInstance方法得到一個真正可以執(zhí)行的Filter實例的。這個我們可以在FilterProvider中得到答案。IFilterProvider是用來定義提供Filter實現(xiàn)的操作,通過它我們可以得到可執(zhí)行的Filter實例,在它的默認(rèn)實現(xiàn)DefaultFilterProvider類中的OnProvidersExecuting方法里調(diào)用了它自身的ProvideFilter方法,看到方法的名字我們可以知道這是提供Filter實例之前的操作,在這里我們可以準(zhǔn)備好Filter實例,我們來看一下OnProvidersExecuting方法的實現(xiàn)[點擊查看源碼👈[5]]
public void OnProvidersExecuting(FilterProviderContext context) {//如果Action描述里的Filter描述存在,即存在Filter定義if (context.ActionContext.ActionDescriptor.FilterDescriptors != null){var results = context.Results;var resultsCount = results.Count;for (var i = 0; i < resultsCount; i++){//循環(huán)調(diào)用了ProvideFilter方法ProvideFilter(context, results[i]);}} }這個方法通過判斷執(zhí)行的Action是否存在需要執(zhí)行的Filter,如果存在則獲取可執(zhí)行的Filter實例,因為每個Action上可能存在許多個可執(zhí)行的Filter,所以這里采用了循環(huán)操作,那么核心就在ProvideFilter方法[點擊查看源碼👈[6]]
public void ProvideFilter(FilterProviderContext context, FilterItem filterItem) {if (filterItem.Filter != null){return;}var filter = filterItem.Descriptor.Filter;//如果Filter不是IFilterFactory實例則是可以直接使用的Filterif (filter is not IFilterFactory filterFactory){//直接賦值FilterfilterItem.Filter = filter;filterItem.IsReusable = true;}else{//如果是IFilterFactory實例//獲取IOC容器實例即IServiceProvider實例var services = context.ActionContext.HttpContext.RequestServices;//調(diào)用IFilterFactory的CreateInstance得到Filter實例filterItem.Filter = filterFactory.CreateInstance(services);filterItem.IsReusable = filterFactory.IsReusable;if (filterItem.Filter == null){throw new InvalidOperationException();}ApplyFilterToContainer(filterItem.Filter, filterFactory);} }通過這個代碼我們就可以看出,這里會判斷Filter是常規(guī)的IFilterMetadata實例還是IFilterFactory實例,如果是IFilterFactory則需要調(diào)用它的CreateInstance方法得到一個可以直接使用的Filter實例,否則就可以直接使用這個Filter了。所以我們注冊Filter的時候可以是任何IFilterMetadata實例,但是真正執(zhí)行的時候需要轉(zhuǎn)換成統(tǒng)一的可直接執(zhí)行的類似ActionFilter的實例。既然ServiceFilterAttribute和TypeFilterAttribute可以實現(xiàn)自IFilterFactory接口,那么我們完全可以自己通過IFilterFactory接口來實現(xiàn)一個Filter創(chuàng)建的工廠,這樣的話為我們創(chuàng)建Filter提供了另一種思路,我們以我們上面自定義的MySampleActionFilter為例,為它創(chuàng)建一個MySampleActionFilterFactory工廠,實現(xiàn)代碼如下
public class MySampleActionFilterFactory : Attribute, IFilterFactory {public bool IsReusable => false;public IFilterMetadata CreateInstance(IServiceProvider serviceProvider){//我們這里模擬通過IServiceProvider獲取依賴的實例IPersonService personService = serviceProvider.GetService<IPersonService>();ILogger<MySampleActionFilter> logger = serviceProvider.GetService<ILogger<MySampleActionFilter>>();//通過依賴構(gòu)造MySampleActionFilter實例并返回return new MySampleActionFilter(personService,logger);} }這樣的話我們可以把MySampleActionFilterFactory同樣作用于上面的示例代碼中去,如下所示,執(zhí)行效果是一樣的
[HttpGet] //[ServiceFilter(typeof(MySampleActionFilter))] [MySampleActionFilterFactory] public List<Person> GetPersons() {return _persons; }全局注冊
之前我們通過示例看到,全局注冊Filter的時候也存在是否將Filter注冊到IOC容器的這種情況。既可以注冊到IOC容器,也可以不注冊到IOC容器,只不過添加過濾器的方法不一樣,看著也挺神奇的,但是一旦用錯IOC就容易注冊了個寂寞。我們知道全局注冊Filter的時候承載Filter的本質(zhì)是一個集合,這個集合的名字叫FilterCollection,這里我們只關(guān)注它的Add方法和AddService方法即可。FilterCollection繼承自Collection<IFilterMetadata>。在.Net Core中微軟的代碼風(fēng)格是用特定的類繼承自已有的泛型操作,這樣的話可以讓開發(fā)者更關(guān)注類功能的本身,而且還可以防止書寫泛型出錯,是個不錯的思路。Add存在好幾個重載方法但是本質(zhì)都是調(diào)用最全的哪一個方法,接下來我們就來先看一下最本質(zhì)的Add方法[點擊查看源碼👈[7]]
public IFilterMetadata Add(Type filterType, int order) {if (filterType == null){throw new ArgumentNullException(nameof(filterType));}//不是IFilterMetadata類型添加會報錯if (!typeof(IFilterMetadata).IsAssignableFrom(filterType)){throw new ArgumentException();}//最終還是將注冊的Filter類型包裝成TypeFilterAttributevar filter = new TypeFilterAttribute(filterType) { Order = order };Add(filter);return filter; }有點意思,豁然開朗了,通過Add方法全局添加的Filter本質(zhì)還是包裝成了TypeFilterAttribute,這也就解釋了為啥我們可以不用再IOC容器中注冊Filter而之前使用Filter了原因就是TypeFilterAttribute幫我們創(chuàng)建了。那接下來我們再來看看AddService方法的實現(xiàn)[點擊查看源碼👈[8]]
public IFilterMetadata AddService(Type filterType, int order) {if (filterType == null){throw new ArgumentNullException(nameof(filterType));}//不是IFilterMetadata類型添加會報錯if (!typeof(IFilterMetadata).IsAssignableFrom(filterType)){throw new ArgumentException();}//最終還是將注冊的Filter類型包裝成ServiceFilterAttributevar filter = new ServiceFilterAttribute(filterType) { Order = order };Add(filter);return filter; }同理AddService本質(zhì)是將注冊的Filter類型包裝成了ServiceFilterAttribute,所以我們?nèi)绻呀?jīng)提前在IOC中注冊了Filter,那么我們只需要直接使用AddService注冊Filter即可。當(dāng)然如果你不知道這個方法而是使用了Add方法也不會報錯,只是IOC容器可能有點寂寞。不過微軟的這思路確實值得我們學(xué)習(xí),這種情況下處理邏輯是統(tǒng)一的,最終都是來自IFilterFactory這個接口。
總結(jié)
????通過本篇文章我們了解了在ASP.NET Core使用Filter的時候,Filter有構(gòu)建實例的方式,即可以將Filter注冊到IOC容器中去,也可以不用注冊。區(qū)別就是你是否可以自行控制Filter實例的生命周期,整體來說微軟的設(shè)計思路還是非常合理的,有助于我們統(tǒng)一處理Filter實例的生成。我們都知道自帶的IOC只支持構(gòu)造注入這樣的話就給特定的Action構(gòu)建Filter的時候帶來了不便,微軟給出了TypeFilterAttribute和ServiceFilterAttribute解決方案,接下來我們就總結(jié)一下它們倆
?TypeFilterAttribute和ServiceFilterAttribute都實現(xiàn)了IFilterFactory接口,只是創(chuàng)建Filter實例的方式不同。?TypeFilterAttribute通過ActivatorUtilities創(chuàng)建Filter實例,雖然它的依賴模塊來自IOC容器,但是Filter實例本身并不受IOC容器管理。?ServiceFilterAttribute則是通過IServiceProvider獲取了Filter實例,這樣整個Filter是受到IOC容器管理的,注入當(dāng)然是基礎(chǔ)操作了。?全局注冊Filter的時候如果沒有將Filter注冊到IOC容器中,則使用Add方法添加過濾器,Add方法的本質(zhì)是將注冊的Filter包裝成TypeFilterAttribute?如果全局注冊Filter的時候Filter已經(jīng)提前注冊到IOC容器中,則使用AddService方法添加過濾器,AddService方法的本質(zhì)是將注冊的Filter包裝成ServiceFilterAttribute
通過上面的描述相信大家能更好的理解Filter本身與IOC容器的關(guān)系,這樣的話也能幫助大家在具體使用的時候知道如何去用,如何更合理的使用。這里我們是用的IActionFilter作為示例,不過沒有沒關(guān)系,只要是實現(xiàn)了IFilterMetadata接口的都是一樣的,即所有的操作都是針對接口的,這也是面向?qū)ο缶幊痰谋举|(zhì)。如果有更多疑問,或作者描述不正確,歡迎大家評論區(qū)討論。
References
[1]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Abstractions/src/Filters/IActionFilter.cs
[2]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/TypeFilterAttribute.cs
[3]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/ServiceFilterAttribute.cs
[4]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Abstractions/src/Filters/IFilterFactory.cs
[5]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/Filters/DefaultFilterProvider.cs#L15
[6]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/Filters/DefaultFilterProvider.cs#L39
[7]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/Filters/FilterCollection.cs#L79
[8]?點擊查看源碼👈:?https://hub.fastgit.org/dotnet/aspnetcore/blob/v6.0.0-rc.2.21480.10/src/Mvc/Mvc.Core/src/Filters/FilterCollection.cs#L163
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core Filter与IOC的羁绊的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#多线程开发-处理子线程中的异常
- 下一篇: Dapr + .NET 实战(十二)服务