一:背景 1. 講故事 過年喝了不少酒,腦子不靈光了,停了將近一個月沒寫博客,今天就當新年開工寫一篇吧。 去年年初有位朋友找到我,說他們的系統會偶發性崩潰,在網上也發了不少帖子求助,沒找到自己滿意的答案,讓我看看有沒有什麼線索,看樣子這是一個牛皮蘚的問題,既然對方有了dump,那就分析起來吧。 二: ...
(Dependency Injection,DI)依賴註入,又稱依賴關係註入,是一種軟體設計模式,也是依賴倒置原則的一種體現。
依賴倒置原則的含義如下
- 上層模塊不依賴下層模塊。二者都依賴抽象
- 抽象不依賴細節
- 細節依賴抽象
依賴註入原則有別於傳統的通過關鍵字new直接依賴下層模塊的形式,以第三方容器註入的形式進行依賴項的管理。依賴註入是實現控制反轉的一種手段,而用來實現依賴註入的技術框架又被成為IOC框架
控制反轉(Inversion of Control,IOC),由於對象之間存在緊密的相互依賴關係,每個對象都需要管理依賴關係的引用,應用程式代碼變得高度耦合且難以拆分。而依賴註入則改變了對象原本的依賴形式。可以實現對依賴關係的控制反轉
.net core 提供原生的IOC框架(命名空間Microsoft.Extension.DependencyInjection),該框架具有輕量和易用性的特點
依賴註入提倡使用面向介面編程
using Microsoft.Extensions.DependencyInjection; using System; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Hello DI IOC!"); var provider = new ServiceCollection() .AddSingleton<MessagePrinter>() .AddSingleton<IWriter, ConsoleWriter>() .BuildServiceProvider(validateScopes: false); var consoleWriter = provider.GetRequiredService<MessagePrinter>(); consoleWriter.WriteLine(); } } public interface IWriter { void WriteLine(string msg); } public class ConsoleWriter : IWriter { public void WriteLine(string msg) { Console.Out.WriteLine(msg); } } public class MessagePrinter { private IWriter _writer; public MessagePrinter(IWriter writer) { _writer = writer; } public void WriteLine() { _writer.WriteLine("Hello World"); } } }View Code
IServiceProvider是依賴註入的核心抽象介面
對於GetRequiredService<T>擴展方法來說,如果服務不可用,就會拋出異常;GetService<T>擴展方法的返回類型是空的,所以是有返回空的可能性的,需要做非空檢查
生命周期
- 單例(Singleton),只會創建一次對象,後續調用復用對象
- 作用域(Scoped),作用域下只生成一個實例,有人將使用的Scoped稱為“請求單例”,表示在每個http請求期間創建一次
- 瞬時(Transient) ,每次調用都是創建新的對象
IServiceProvider對象提供了CreateSocpe擴展方法 使用CreateSocpe擴展方法會創建一個相應的服務範圍,這個服務範圍代表子容器,這個子容器獲取相應的IServiceProvider對象
IServiceProvider有兩種定義:一種是根容器(Root Scope)中的IServiceProvider對象,是位於應用程式頂端的容器,一般被稱為ApplicationServices;另一種是通過IServiceScopeFactory服務創建的帶有服務範圍的IServiceProvider對象,而對於IServiceScope對象來說,擁有的是一個“範圍”性的IServiceProvider對象,只可以擁有一個根容器
ASP.NET Core的作用域,在asp.net core中,每個請求都會創建一個全新的Scope(作用域)服務,在這個請求過程中創建的服務實例都會保存在當前的IServiceProvider對象上
ServiceDescriptor對象用於註冊指定的服務時,對服務註冊項進行描述,
作用域驗證,例如,應用程式有一個Context對象,開發人員通常會將其註冊為Socped生命周期
控制台實例創建ServiceCollection對象,調用AddSocped擴展方法註冊。調用ISerivceprocider對象之後調用GetRequiredService<T>擴展方法來獲取實例
應該從IServiceScope對象中解析,而不是從IServiceProvider對象中解析,在asp.net core請求中框架會自動創建ServiceProviderServiceExtensions.CreateScope作用域容器,不是asp.net core 可以自行創建一個作用域