.NET Core ASP.NET Core Basic 1-2 控制反转与依赖注入
本節(jié)內(nèi)容為控制反轉(zhuǎn)與依賴注入
簡介
控制反轉(zhuǎn)IOC
這個內(nèi)容事實上在我們的C#高級篇就已經(jīng)有所講解,控制反轉(zhuǎn)是一種設(shè)計模式,你可以這樣理解控制反轉(zhuǎn),假設(shè)有一個人他有一部A品牌手機,他用手機進行聽歌、打游戲,那么你可以創(chuàng)建一個手機類和一個人類
class APhone : IPhone {public string Owner{get;set;}public Phone(string own){Owner = own;}void Play(){}void Music(){} } class Man {public string Name{get;set;}void Game(){var p = new APhone(Name);p.Play();} }事實上這段代碼的耦合度是比較高的?它使用的是正轉(zhuǎn),也就是我需要什么東西的時候我就自己創(chuàng)建一個這個東西。為什么說他不好呢,如果有一天這個人決定再也不使用A品牌手機了,他決定以后只使用B品牌。那么也就意味著整個的Man類使用過APhone類的地方都需要更改。這是一個非常麻煩的事情,我們這個時候就需要運用我們的IOC控制反轉(zhuǎn)了。我們將實例或者是需要使用的對象的創(chuàng)建交給你的調(diào)用者,自己只負責使用,其它人丟給你依賴的這個過程理解為注入。
控制反轉(zhuǎn)的核心就是——原本我保存使用我自己的東西,現(xiàn)在我把控制權(quán)交給我的上級,我需要使用的時候再向他要。這個時候,接口的作用不言而喻,A繼承了Phone接口,B也繼承了,假定我們一開始就使用Phone接口去創(chuàng)建不同的A,B對象,那么是不是可以有效的切換AB對象呢?
依賴注入
依賴注入體現(xiàn)的是一個IOC(控制反轉(zhuǎn)),它非常的簡單,我們之前的Man類代碼中使用的是正轉(zhuǎn)的方式,也就是我要一個對象,那么我就創(chuàng)建一個。現(xiàn)在我們使用依賴注入就是將我們對這個對象的控制權(quán)交給上一級接口,也就成為了這種,我想要一個對象,我就向上級發(fā)出請求,上級就給我創(chuàng)建了一個對象。我們通常使用構(gòu)造函數(shù)注入的方式進行依賴的注入。
上文的代碼就會變成
class Man {private readonly IPhone _phone;public Man(IPhone phone){_phone = phone;} }假設(shè)這個時候你需要將手機換成B品牌,那么只需要再注入的地方傳入B品牌的對象即可了。
容器
但是現(xiàn)在又出現(xiàn)了一個新的問題,假設(shè)說這個類有100個使用該接口的依賴,如果,我們是不是要在100個地方做這樣的事情?控制是反轉(zhuǎn)了,依賴的創(chuàng)建也移交到了外部。現(xiàn)在的問題是依賴太多,我們需要一個地方統(tǒng)一管理系統(tǒng)中所有的依賴,這個時候,我們就使用容器進行集中的管理
容器負責兩件事情:
綁定服務(wù)與實例之間的關(guān)系
獲取實例,并對實例進行管理(創(chuàng)建與銷毀)
使用
說了那么多,我們?nèi)绾卧?NET Core中使用我們的依賴注入呢?這里我們針對的是所有的.NET Core的應(yīng)用,在.NET Core中依賴注入的核心分為兩個組件:位于Microsoft.Extensions.DependencyInjection命名空間下的IServiceCollection和 IServiceProvider。
其中
IServiceCollection 負責注冊
IServiceProvider 負責提供實例
在默認的容器ServiceCollection中有三個方法
.AddTransient<I,C>()
.AddSingleton<I,C>()
.AddScoped<I,C>()
這里就不得不提一下我們依賴注入的三種生命周期了
Singleton指的是單例模式,也就是說,在整個程序運轉(zhuǎn)期間只會生成一次
Transient指每一次GetService都會創(chuàng)建一個新的實例
Scope指在同一個Scope內(nèi)只初始化一個實例 ,可以理解為( 每一個request級別只創(chuàng)建一個實例,同一個http request會在一個 scope內(nèi))
我們可以嘗試使用控制臺項目來模擬依賴注入的原理,也就是說我們直接從容器獲取我們對象實例,并且我們使用Guid進行唯一性的標記。
interface IPhoneScope{Guid Guid { get; }}interface IPhoneSingleton{Guid Guid { get; }}interface IPhoneTransient{Guid Guid { get; }}class PhoneService:IPhoneScope,IPhoneSingleton,IPhoneTransient{public PhoneService(){this._guid = Guid.NewGuid();}public PhoneService(Guid guid){this._guid = guid;}private Guid _guid;public Guid Guid => this._guid;}然后,在我們的主函數(shù)中
namespace DI_AND_IOC {class Program{static void Main(string[] args){var services = new ServiceCollection().AddScoped<IPhoneScope, PhoneService>().AddTransient<IPhoneTransient, PhoneService>().AddSingleton<IPhoneSingleton, PhoneService>();var provider = services.BuildServiceProvider();using (var scope = provider.CreateScope()){var p = scope.ServiceProvider;var scopeobj1 = p.GetService<IPhoneScope>();var transient1 = p.GetService<IPhoneTransient>();var singleton1 = p.GetService<IPhoneSingleton>();var scopeobj2 = p.GetService<IPhoneScope>();var transient2 = p.GetService<IPhoneTransient>();var singleton2 = p.GetService<IPhoneSingleton>();Console.WriteLine($"scope1: {scopeobj1.Guid},\n" +$"transient1: {transient1.Guid}, \n" +$"singleton1: {singleton1.Guid}\n");Console.WriteLine($"scope2: {scopeobj2.Guid}, \n" +$"transient2: {transient2.Guid},\n" +$"singleton2: {singleton2.Guid}\n");}using (var scope = provider.CreateScope()){var p = scope.ServiceProvider;var scopeobj3 = p.GetService<IPhoneScope>();var transient3 = p.GetService<IPhoneTransient>();var singleton3 = p.GetService<IPhoneSingleton>();Console.WriteLine($"scope3: {scopeobj3.Guid}, \n" +$"transient3: {transient3.Guid},\n" +$"singleton3: {singleton3.Guid}");}}} }你應(yīng)該會得到類似以下的數(shù)據(jù)
scope1: 096d38e5-0c7b-4e50-9c79-241fb18a56ed, transient1: 289ebd11-8159-4f22-b53e-ed738a317313, singleton1: b453b7f5-3594-4b66-99c8-a72763abaa83scope2: 096d38e5-0c7b-4e50-9c79-241fb18a56ed, transient2: 212ad420-e54c-4dd6-9214-abe91aacdd9c, singleton2: b453b7f5-3594-4b66-99c8-a72763abaa83scope3: 688b6ffd-a8c1-47f4-a20a-872c2285d67c, transient3: 3d09997d-fffb-43d1-9e53-ccf9771c819d, singleton3: b453b7f5-3594-4b66-99c8-a72763abaa83可以發(fā)現(xiàn),singleton對象是不會發(fā)生改變的,而scope對象在創(chuàng)建新的scope之后就發(fā)生了改變,而transient對象每一次請求都在發(fā)生改變。
需要注意的是,在控制臺項目使用容器服務(wù)需要引入 *** Microsoft.Extensions.DependencyInjection *** 程序集,你可以在引入中導(dǎo)入該dll
通過對注入服務(wù)的生命周期管控,在一些ASP.NET Core項目中,有些類(服務(wù))有可能跨越了多個Action或者Controller,那么我們正確的使用生命周期,我們可以盡可能的節(jié)省內(nèi)存,即能減少實例初始化的消耗。
在ASP.NET Core中的使用
在ASP.NET Core中,我們使用依賴注入非常的簡單,在StartUp類中的ConfigureServices方法中已經(jīng)為我們構(gòu)建好了容器,我們只需要做類似于這樣的操作
services.AddScoped<IPhoneScope, PhoneService>(); services.AddDbContext<DbContext>(); services.AddMVC();如果你需要在控制器中注入服務(wù),官方的推薦方案是使用構(gòu)造函數(shù)注入
public IPhoneScope _ips; public Controller(IPhoneScope ips) {_ips = ips; }特別的,你如果使用MVC的Razor頁面進行注入的話,那么輸入以下指令
如果我的文章幫助了您,請您在github.NETCoreGuide項目幫我點一個star,在博客園中點一個關(guān)注和推薦。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的.NET Core ASP.NET Core Basic 1-2 控制反转与依赖注入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员过关斩将--互联网人必备知识coo
- 下一篇: 微软发布了开发社区采用.NET Stan