ASP.NET Core - 在ActionFilter中使用依赖注入
上次ActionFilter引發(fā)的一個(gè)EF異常,本質(zhì)上是對Core版本的ActionFilter的知識掌握不夠牢固造成的,所以花了點(diǎn)時(shí)間仔細(xì)閱讀了微軟的官方文檔。發(fā)現(xiàn)除了IActionFilter、IAsyncActionFilter的問題,還有一個(gè)就是依賴注入在ActionFilter上的使用也是需要注意的地方。
當(dāng)我們的ActionFilter需要使用某個(gè)Service的時(shí)候,我們一般會通過構(gòu)造函數(shù)注入。
演示一下,首先自定義一個(gè)ActionFilter,通過構(gòu)造函數(shù)注入IMyService:
但是我們在使用Attribute的時(shí)候VS直接給出紅色提示,需要傳入構(gòu)造函數(shù)的參數(shù),否則無法編譯過去。
當(dāng)然我們可以直接new一個(gè)MyService來當(dāng)做參數(shù),但是很顯然這樣就失去了注入的那些好處了。
在ActionFilter中使用依賴注入
在ASP.NET Core的ActionFilter中使用依賴注入主要有兩種方式:
ServiceFilterAttribute
TypeFilterAttribute
ServiceFilterAttribute
使用ServiceFilterAttribute可以使你的ActionFilter完成依賴注入。其實(shí)就是把你要用的ActionFilter本身注冊為一個(gè)Service注冊到DI容器中。通過ServiceFilter從容器中檢索你的ActionFilter,并且注入到需要的地方。所以第一步就是要注冊你的ActionFilter:
public void ConfigureServices(IServiceCollection services){services.AddScoped<IMyService,MyService>();services.AddScoped(typeof(FilterInjectAttribute));services.AddControllers();services.AddRazorPages();}然后新建一個(gè)Controller,在Action上使用ServiceFilter:
[ServiceFilter(typeof(FilterInjectAttribute))]public string DI(){Console.WriteLine("HomeController method DI running .");return "DI";}運(yùn)行一下,在瀏覽器里訪問下對應(yīng)的path,可以看到MyService已經(jīng)注入到FilterInjectAttribute中:
ServiceFilterAttribute的IsReusable屬性:
ServiceFilter有一個(gè)屬性叫IsReusable。從字面意思也很好理解,就是是否可重用的意思。顯而易見如果這個(gè)屬性設(shè)置為True,那么多個(gè)請求就會復(fù)用這個(gè)ActionFilter,這就有點(diǎn)像是單例的意思了。
[ServiceFilter(typeof(FilterInjectAttribute), IsReusable = true)]public string DI(){Console.WriteLine("HomeController method DI running .");return "DI";}運(yùn)行一下,多次在瀏覽器中訪問對應(yīng)的action的path,可以看到FilterInjectAttribute的構(gòu)造函數(shù)只會執(zhí)行一次。
這里有一個(gè)重要提示, ASP.NET Core runtime 并不保證這個(gè)filter是真正的單例。所以不要試圖使用這個(gè)屬性來實(shí)現(xiàn)單例,并且業(yè)務(wù)系統(tǒng)依賴這個(gè)單例。
TypeFilterAttribute
使用TypeFilterAttribute也可以使你的ActionFilter完成依賴注入。它跟ServiceFilterAttribute差不多,但是使用TypeFilterAttribute注入的ActionFilter并不從DI容器中查找,而是直接通過Microsoft.Extensions.DependencyInjection.ObjectFactory來實(shí)例化對象。所以我們的FilterInjectAttribute不需要提前注冊到DI容器中。首先注釋掉FilterInjectAttribute的注冊代碼:
public void ConfigureServices(IServiceCollection services){services.AddScoped<IMyService,MyService>();//services.AddScoped(typeof(FilterInjectAttribute));services.AddControllers();services.AddRazorPages();}改用TypeFilterAttribute:
[TypeFilter(typeof(FilterInjectAttribute))]public string DI(){Console.WriteLine("HomeController method DI running .");return "DI";}運(yùn)行一下,在瀏覽器里訪問下對應(yīng)的path,可以看到MyService已經(jīng)注入到FilterInjectAttribute中:
TypeFilterAttribute的IsReusable屬性:
跟上面的ServiceFilter一樣,ASP.NET Core runtime 并不保證這個(gè)filter是真正的單例,這里就不多啰嗦了。
TypeFilterAttribute的Arguments屬性:
Arguments參數(shù)是TypeFilterAttribute跟ServiceFilterAttribute的一個(gè)重要區(qū)別,ServiceFilterAttribute并沒有這屬性。Arguments類型為object數(shù)組。通過TypeFilterAttribute實(shí)例化的ActionFilter,如果它的構(gòu)造器中的參數(shù)類型在DI容器中找不到,會繼續(xù)在Arguments參數(shù)列表里按順序獲取。
改一下FilterInjectAttribute構(gòu)造器多加入2個(gè)參數(shù),并且保證這2個(gè)參數(shù)無法從DI中取到:
在使用的時(shí)候傳入兩個(gè)參數(shù):
[TypeFilter(typeof(FilterInjectAttribute), Arguments = new object[] { "HAHA", "HOHO" })]public string DI(){Console.WriteLine("HomeController method DI running .");return "DI";}運(yùn)行一下看到兩個(gè)參數(shù)被傳入了FilterInjectAttribute的構(gòu)造器:
總結(jié)
ActionFilterAttribute的依賴注入可以通過ServiceFilterAttribute,TypeFilterAttribute來實(shí)現(xiàn)
ServiceFilterAttribute是通過DI容器來管理ActionFilterAttribute;TypeFilterAttribute則是通過一個(gè)工廠直接實(shí)例化,所以使用前不需要注冊到DI容器中。
IsReusable屬性可以實(shí)現(xiàn)類似單例的功能,但是運(yùn)行時(shí)并不保證唯一單例。
TypeFilterAttribute的Arguments屬性可以作為參數(shù)列表。當(dāng)實(shí)例化ActionFilterAttribute的時(shí)候如果構(gòu)造器參數(shù)類型沒有在DI容器中注冊那么會嘗試從Arguments列表中取。
關(guān)注我的公眾號一起玩轉(zhuǎn)技術(shù)
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core - 在ActionFilter中使用依赖注入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 Tye 辅助开发 k8s 应用竟如
- 下一篇: .NET工资低?那肯定是你打开的方式不正