1、前言
面向物件設計(OOD)里有一個重要的思想就是依賴倒置原則(DIP),并由該原則牽引出依賴注入(DI)、控制反轉(IOC)及其容器等概念,在學習Core依賴注入、服務生命周期之前,下面讓我們先了解下依賴倒置原則(DIP)、依賴注入(DI)、控制反轉(IOC)等概念,然后再深入學習Core依賴注入服務,
2、依賴倒置原則(Dependency Inversion Principle, DIP)
抽象不應該依賴于細節,細節應當依賴于抽象,高層模塊不依賴于低層模塊的實作,而低層模塊依賴于高層模塊定義的介面,一般來講,就是高層模塊定義介面,低層模塊負責具體的實作,針對介面編程而不是針對細節編程
3、什么是依賴注入(Denpendency Injection)
3.1、依賴
人與人之間都有依賴(尤其我,就是離不開女人哈哈)何況軟體呢?所謂依賴就是:當一個類需要另一個類協作來完成作業的時候就產生了依賴,比如用戶登錄,我們在控制器中UserController要完成用戶登錄、注冊、修改密碼等等事情、其中操作到資料庫的(登錄)我們用EF來完成,這里我們封裝了一個EFLogin,這里的UserController就有一個ILogin的依賴,需要知道的是這里依賴于一個抽象為不是具體的某一個實作,所以給EFLogin定義了一個介面ILogin抽象了EFLogin的行為

3.2、注入
注入體現的是一個IOC(控制反轉的的思想),
public interface IUser { string BB(); } public class User : IUser { public string BB() { return "LP整天只會BB"; } } public class ShowInfo { IUser user = new User(); public void UserBB() { user.BB(); } }
當我們呼叫ShowInfo的時候,是通過IUser介面實體化一個User類去實作其方法的這叫控制正傳, 但是大濕兄說,我們不應該創建User類,而是讓呼叫者給你傳遞,于是你通過建構式讓外界把這兩個依賴給你,把依賴的創建丟給其它人,自己只負責使用,其它人丟給你依賴的這個程序理解為注入其它人丟給你依賴的這個程序理解為注入,也叫控制反轉(IOC),
public interface IUser { string BB(); } public class User : IUser { public string BB() { return "LP整天只會BB"; } } public class ShowInfo2 { private readonly IUser _user; public ShowInfo2 (IUser user) { _user = user; } public void UserBB() { _user.BB(); } }
3.3、為什么要使用依賴注入?
使用依賴注入我們可以很好的管理類跟類之間的依賴,在我們設計應用程式的時候遵循這幾原則,確保代碼的可維護性和擴展性;另外在Core的架構中依賴注入提供了物件創建和生命周期管理的核心能力,各個組件之間的相互協作也是由依賴注入框架來實作的
4、服務生命周期
在ConfigureServices方法中的容器注冊每個應用程式的服務,Asp.Core都可以為每個應用程式提供三種服務生命周期:
Transient(暫時):每次請求都會創建一個新的實體,這種生命周期最適合輕量級,無狀態服務,
Scoped(作用域):在同一個作用域內只初始化一個實體 ,可以理解為每一個請求只創建一個實體,同一個請求會在一個作用域內,在Scooped的生存周期內,如果容器釋放 它也就被釋放了
Singleton(單例):整個應用程式生命周期以內只創建一個實體,后續每個請求都使用相同的實體,如果應用程式需要單例行為,建議讓服務容器管理服務的生命周期,而不是在自己的類中實作單例模式,
為了演示生命周期和注冊選項之間的差異,請考慮以下代碼:

IGuid介面回傳一個Guid
public interface IGuid { Guid GetGuid { get; } }
介面IScopedService、ISingletonService、ITransientService、都繼承介面IGuid
public interface IScopedService:IGuid { } public interface ISingletonService: IGuid { } public interface ITransientService: IGuid { }
GuidShow類繼承介面IScopedService、ISingletonService、ITransientService
public class GuidShow : IScopedService, ISingletonService, ITransientService { public GuidShow() : this(Guid.NewGuid()) { } public GuidShow(Guid id) { GetGuid = id; } public Guid GetGuid { get; private set; } }
在Starup里面注冊
public void ConfigureServices(IServiceCollection services) { #region//注冊不同生命周期的服務 services.AddSingleton<ISingletonService, SingletonService>(); services.AddTransient<ITransientService, TransientService>(); services.AddScoped<IScopedService, ScopedService>(); #endregion services.AddControllers(); }
在WeatherForecastController Api里寫一個Api
FromServices就是從容器里面獲取我們的物件 每個物件都獲取兩邊來來對比每個生命周期是怎么樣的
[ApiController] [Route("[controller]/[action]")] //路由 //API [HttpGet] public string GetService( [FromServices] IScopedService scoped1, [FromServices] IScopedService scoped2, [FromServices] ITransientService transient1, [FromServices] ITransientService transient2, [FromServices] ISingletonService singleton, [FromServices] ISingletonService singleton2) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine($"作用域1-->{scoped1.GetGuid}"); Console.WriteLine($"作用域2-->{scoped2.GetGuid}"); Console.WriteLine(); Console.WriteLine(); Console.WriteLine($"瞬時1-->{transient1.GetGuid}"); Console.WriteLine($"瞬時2-->{transient2.GetGuid}"); Console.WriteLine(); Console.WriteLine(); Console.WriteLine($"單例1-->{singleton.GetGuid}"); Console.WriteLine($"單例2-->{singleton2.GetGuid}"); Console.WriteLine("===========分割線====================="); Console.WriteLine(); Console.WriteLine(); return "成功"; }
修改應用程式啟動

啟動應用程式

可以看出來單例跟作用域的都是一樣的Guid 只有瞬時的不一樣 再次重繪瀏覽器

單例的沒有改變所以
Transient(暫時):每次呼叫服務的時候都會創建一個新的實體
Scoped(作用域):一次請求(Action)內物件實體是相同的,但每次請求會產生一個新實體,
Singleton(單例):首次請求初始化同一個實體,后續每次請求都使用同一個實體,相當于在整個應用Application中只實體化一次實體,常見的單例模式,
下面是其他的注冊
#region//工程模式注冊 單例作用域、瞬時 都可以用 services.AddSingleton<ISingletonService>(s=> { return new SingletonService(); });
#region//嘗試注冊 //注冊過了就不在注冊了 //using Microsoft.Extensions.DependencyInjection.Extensions; services.TryAddScoped<IScopedService, ScopedService>(); #endregion
#region//移除注冊 移除所有IScopedService的注冊 不同實作的
services.RemoveAll<IScopedService>(); #endregion
注冊泛型 先寫一個泛型類
public interface ITypeT<T> { } public class TypeT<T> : ITypeT<T> { public T GetT { get; } public TypeT(T getT) { this.GetT = getT; } }
創建一個api Test
[Route("api/[controller]/[action]")] [ApiController] public class TestController : ControllerBase { public ITypeT<IScopedService> _typeT; public TestController(ITypeT<IScopedService> typeT) { _typeT = typeT; } [HttpGet] public string TestGet() { return _typeT.GetHashCode().ToString(); } }
注冊一下 里面具體的引數不用謝 實作的時候只要帶入某個具體的類就可以了,第一個引數服務的額型別,第二個引數服務的實作型別
services.AddScoped(typeof(ITypeT<>),typeof(TypeT<>));
地址欄輸入https://localhost:5001/api/test/testGet
看斷點

GetT他得到的是ScopedService
5、依賴注入的方式
5.1、建構式注入
我們可以在定義的Controller中以建構式注入的方式注入所需的服務,他的服務是大部分介面都需要的話就用它
public ITypeT<IScopedService> _typeT; public TestController(ITypeT<IScopedService> typeT) { _typeT = typeT; }
5.2、FromServices
上面的GetService就是這種方式注入的,這個服務只是在某一個介面下用FromServices
當然還有其他的注入方式就不在研究了,
原文鏈接:https://www.cnblogs.com/w5942066/p/12808405.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/36102.html
標籤:.NET Core
