asp.net core 依賴註入實現全過程粗略剖析(1)

来源:https://www.cnblogs.com/zhiyong-ITNote/archive/2018/07/29/9385026.html
-Advertisement-
Play Games

轉載請註明出處: https://home.cnblogs.com/u/zhiyong-ITNote/ 常用擴展方法 註入依賴服務: new ServiceCollection().AddSingleton<IApplicationBuilder, ApplicationBuilder>(); // ...


轉載請註明出處: https://home.cnblogs.com/u/zhiyong-ITNote/

常用擴展方法 註入依賴服務:

new ServiceCollection().AddSingleton<IApplicationBuilder, ApplicationBuilder>();
View Code

// AddSingleton多個重載方法 源碼

public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}

return services.AddSingleton(typeof(TService), typeof(TImplementation));
}

// Singleton模式 最終的調用
public static IServiceCollection AddSingleton(
this IServiceCollection services,
Type serviceType,
Type implementationType)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}

if (serviceType == null)
{
throw new ArgumentNullException(nameof(serviceType));
}

if (implementationType == null)
{
throw new ArgumentNullException(nameof(implementationType));
}

return Add(services, serviceType, implementationType, ServiceLifetime.Singleton);
}

// 所有的Addxxx 最終都是調用Add方法,將ServiceDescriptor添加到IServiceCollection中:
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return collection;
}

// IServiceCollection源碼:
public interface IServiceCollection : IList<ServiceDescriptor>
{}
View Code

如上,我們一般在ConfigureService中使用Addxxx將服務註入框架的過程。大概做個總結,其實就是屌用IServiceCollection的Addxxx 擴展方法,隨後調用Add方法,初始化一個ServiceDescriptor,參數是我們註入的介面和類,還有就是生命周期。隨後添加到IServiceCollection中,根據該介面的定義就是一個ServiceDescriptor的集合。

我們看看ServiceProvider的源碼:

 public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
    {
        private readonly IServiceProviderEngine _engine;

        private readonly CallSiteValidator _callSiteValidator;

        internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
        {
            IServiceProviderEngineCallback callback = null;
            if (options.ValidateScopes)
            {
                callback = this;
                _callSiteValidator = new CallSiteValidator();
            }
            switch (options.Mode)
            {
                case ServiceProviderMode.Dynamic:
                    _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
                    break;
                case ServiceProviderMode.Runtime:
                    _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
                    break;
#if IL_EMIT
                case ServiceProviderMode.ILEmit:
                    _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback);
                    break;
#endif
                case ServiceProviderMode.Expressions:
                    _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
                    break;
                default:
                    throw new NotSupportedException(nameof(options.Mode));
            }
        }

        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public object GetService(Type serviceType) => _engine.GetService(serviceType);

        /// <inheritdoc />
        public void Dispose() => _engine.Dispose();

        void IServiceProviderEngineCallback.OnCreate(IServiceCallSite callSite)
        {
            _callSiteValidator.ValidateCallSite(callSite);
        }

        void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
        {
            _callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope);
        }
    }
View Code

該類就是初始化並獲取如下屬性:

/// <inheritdoc />
public ServiceLifetime Lifetime { get; }

/// <inheritdoc />
public Type ServiceType { get; }

/// <inheritdoc />
public Type ImplementationType { get; }

/// <inheritdoc />
public object ImplementationInstance { get; }

/// <inheritdoc />
public Func<IServiceProvider, object> ImplementationFactory { get; }
View Code

到此,我們的服務註入到asp.net core框架中就完事了,那麼服務的實例化呢?

首先我們理下思路,IServiceProvider介面對應的實現是ServiceProvider,這個類就是實例化了IServiceProvider介面,而IServiceProvider介面只有一個方法:

public object GetService(Type serviceType);

該方法就是獲取註入的服務。但是ServiceProvider類不單單是獲取註入的服務,服務的實例化還是在該類中實現的,我們看下:

public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
{
private readonly IServiceProviderEngine _engine;

private readonly CallSiteValidator _callSiteValidator;

internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = null;
if (options.ValidateScopes)
{
callback = this;
_callSiteValidator = new CallSiteValidator();
}
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
_engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
_engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
#if IL_EMIT
case ServiceProviderMode.ILEmit:
_engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback);
break;
#endif
case ServiceProviderMode.Expressions:
_engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new NotSupportedException(nameof(options.Mode));
}
}

/// <summary>
/// Gets the service object of the specified type.
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public object GetService(Type serviceType) => _engine.GetService(serviceType);

/// <inheritdoc />
public void Dispose() => _engine.Dispose();

void IServiceProviderEngineCallback.OnCreate(IServiceCallSite callSite)
{
_callSiteValidator.ValidateCallSite(callSite);
}

void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
{
_callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope);
}
}
View Code

可以看到該類的構造函數中就是實例化服務的過程了。很直白的可以看出我們常見的幾種方法來實例化類:反射,Emit,表達式樹等...

目前也算是交代清楚了相關的類。那麼框架具體是如何來實例化的呢?整個的流程是怎麼樣的。篇2再敘

轉載請註明出處: https://home.cnblogs.com/u/zhiyong-ITNote/

源碼地址:https://github.com/aspnet/DependencyInjection  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題意 給出三個已經排好序的數組$a, b, c$ 在$100$次詢問內找出第$k$小的元素 Sol 一種很顯然的$log^2n$的做法:首先在$a$中二分,然後再$b,c$中二分。這樣可以得到$60$分的好成績。 然而這演算法就沒什麼優化的空間了。。。 考慮另一種做法。 我們每次對三個數組詢問第$\f ...
  • 有時候,可能會有一些類似這樣的需求,具體如圖所見,取首字母。 ...
  • 前言 Spring框架為什麼如此流行? 原來Spring框架解決了一個很關鍵的問題,它可以把對象之間的依賴關係轉為用配置文件來管理,也就是它的依賴註入機制。IOC容器用來管理這些Bean,管理Bean的關係以及生命周期,然而這與之前將應用程式主動new對象不同,Spring實現使用IOC容器創建對象 ...
  • 接著 上篇 目前也算是交代清楚了相關的類。那麼框架具體是如何來實例化的呢?整個的流程是怎麼樣的。 我們參考源碼中的Test文件夾來看看: var collection = new ServiceCollection(); collection.AddTransient<DependOnNonexis ...
  • 本文主要以一個簡單的小例子,描述C# Winform程式異常關閉時,如何進行捕獲,並記錄日誌。 ...
  • 誤解一:併發就是多線程 實際上多線程只是併發編程的一種形式,在C 中還有很多更實用、更方便的併發編程技術,包括非同步編程、並行編程、TPL 數據流、響應式編程等。 誤解二:只有大型伺服器程式才需要考慮併發 伺服器端的大型程式要響應大量客戶端的數據請求,當然要充分考慮併發。但是桌面程式和手機、平板等移動 ...
  • 1. 程式集和CIL: 程式集是由.NET語言的編譯器接受源代碼文件產生的輸出文件,通常分為 exe和dll兩類,其中exe包含Main入口方法可以雙擊執行,dll則需要被其他程式集調用執行。 CIL(Common Intermediate Language): 公共中間語言①,需要被編譯成二進位機 ...
  • 依賴註入(DI)不是一個新的話題,它的出現是伴隨著系統解耦的需要而幾乎必然產生的。 在SOLID設計原則中,DIP(Dependency inversion principle)——依賴倒置,規定了“需依賴抽象,而非實現”的準則,該原則主要目的是通過引入抽象(比如介面)的方式降低模塊之間的耦合性。與 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...