目錄:
一、什么是依賴注入
1.1、什么是依賴?
1.2、 什么是注入?
1.3、依賴注入解決的問題
二、服務的生命周期(.Net Core DI)
三、替換默認服務容器
3.1、為什么替換默認服務容器?
3.2、如何替換服務容器
一、什么是依賴注入
1、 什么是依賴
Rely類
public class Rely { public Task Test(string testMessage) { Console.WriteLine(testMessage); return Task.FromResult(0); } }
Output類
public class Output { Rely rely = new Rely(); public async Task Out() { await rely.Test("這是一個測試消息"); } }
Output類需要Rely類來幫助它實現輸出的功能,這樣Output類對Rely類產生了依賴,可以理解為Output依賴於Rely
依賴的一個設計原則:依賴於抽象,而不是具體的實現,這個后面會具體解釋的
2、 什么是注入
修改Output類
public class Output { private Rely _rely; public Output(Rely rely) { _rely = rely; } public async Task Out() { await _rely.Test("這是一個測試消息"); } }
在這里Output類不去實例化Rely類,而是通過其他人傳遞給我,我只用就好。到底怎么理解注入呢?
簡單來說就是別人對依賴創建實例化,我自己只負責使用,別人創建好了給我使用,這么一個過程可以理解為注入
這里主要體現了控制反轉 (IoC)的思想,什么是IOC ?我們看看下面的圖就好理解了
直接依賴關系在運行的時候A調用B,B調用C,編譯的時候A取決於B,B取決於C。
而在反轉依賴關系中, A可以調用B實現的抽象上的方法,讓A可以在運行時調用B,而B又在編譯時依賴於A控制的接口,程序運行時流程跟直接依賴關系一樣。但是插入了接口意味着可以輕松的有不同實現
3、 依賴注入解決的問題
依賴注入主要體現了IOC思想,IOC將實現詳細信息編寫為依賴並且實現了更高級的抽象,因此程序測試性,維護性,模塊化程度都更高了。這也就對應了剛剛的那個設計規則--依賴於抽象,而不是具體的實現。
那么依賴注入到底解決了哪些問題呢?
問題一:在直接依賴關系中如果A類需要更換為其他實現,那么就必須得修改B類
問題二:如果有多個依賴B類的類,那么將會實例化多個配置,這樣代碼會比較分散和冗余
問題三:這種實現方法很難實現單元測試
解決這些問題的辦法:
一:使用了接口抽象話依賴關系的實現,改動實現只需要改動注入的地方即可
二:注冊服務容器中的依賴關系,有多處需要不許多出實例化配置,直接在Startup.ConfigureServices中注冊即可
二、服務的生命周期(.Net Core DI)
在.NET Core中DI的核心分為兩個組件:IServiceCollection和 IServiceProvider。
-
- IServiceCollection---負責注冊
- IServiceProvider---負責提供實例
在Startup.cs中ConfigureServices中注冊服務
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();//單例生存期 services.AddScoped<IHttpContextAccessor, HttpContextAccessor>();//范圍生存期 services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();//暫時生存期 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
1、 Transient(暫時生存期)--暫時生存期服務是每次從服務容器進行請求時創建的。 這種生存期適合輕量級、 無狀態的服務。
暫時生存期會在每次請求的時候創建一個實例
2、 Scoped(范圍生存期)--范圍生存期服務是每個客戶端連接時創建的一次實例
范圍生存期會在客戶端連接時創建一次實例,然后每次請求的實例都是相同的
3、 Singleton(單例生存期)--單例生存期會在程序第一次請求是創建一次實例
單例生存期僅會在第一次連接時創建一次實例,所有整個程序使用的實例都是同一個實例
三、替換默認服務容器
1、 為什么替換默認服務容器
我們可以首先理解下什么是服務容器—依賴注入把依賴的創建給了別人,別人創建好了再給我們使用。那么在哪里創建依賴呢?或者說在那里管理依賴呢?這里就有了容器這個概念,負責管理系統中所有的依賴。
那么我們為什么要替換容器呢?
內置的服務容器足夠實現一些小型的項目或滿足大多數的消費者,但是遇到大型的項目就比較麻煩了,依賴較多,內置的服務容器就顯得有點短板了。當我們遇到這些問題的時候就可以考慮替換默認服務容器。
2、 如何替換服務容器
這里我們說下替換服務容器為Autofac。
安裝適當的包
-
- Autofac
- Autofac.Extensions.DependencyInjection
在 Startup.ConfigureServices 中配置返回 為IServiceProvider:
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); // Add other framework services // Add Autofac var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterModule<DefaultModule>(); containerBuilder.Populate(services); var container = containerBuilder.Build(); return new AutofacServiceProvider(container); }
如果要使用第三方容器的話, Startup.ConfigureServices 必須返回 IServiceProvider。
然后我們在 DefaultModule
中配置 Autofac
public class DefaultModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<CharacterRepository>().As<ICharacterRepository>(); } }
歡迎大家掃描下方二維碼,和我一起學習更多的知識😊