MEF 插件式開發 - DotNetCore 中強大的 DI

来源:https://www.cnblogs.com/hippieZhou/archive/2018/08/14/9460223.html
-Advertisement-
Play Games

[TOC] 背景敘述 在前面幾篇 MEF 插件式開發 系列博客中,我分別在 和 兩種框架下實驗了 MEF 的簡單實驗,由於 由來已久,因此基於該框架下衍生出的很多優秀的 MEF 框架較多。但是對於 來說,情況有所不同,由於它本身對 DI 內置並提供支持,因此我嘗試使用它的全新 依賴註入(DI) 來做 ...


目錄


背景敘述

在前面幾篇 MEF 插件式開發 系列博客中,我分別在 DotNet FrameworkDotNet Core 兩種框架下實驗了 MEF 的簡單實驗,由於 DotNet Framework 由來已久,因此基於該框架下衍生出的很多優秀的 MEF 框架較多。但是對於 DotNet Core 來說,情況有所不同,由於它本身對 DI 內置並提供支持,因此我嘗試使用它的全新 依賴註入(DI) 來做一些實驗。

動手實驗

要想讓程式支持 DI,就需要為項目安裝 Package:

Install-Package Microsoft.Extensions.DependencyInjection -Version 2.1.1 

然後,我們就可以使用強大的 DI 了。

DotNet Core,所有服務的註冊都是統一放到一起的,而這個就是由 ServiceCollection 來接收的;其次,當服務註冊完畢後,還需要對服務進行初始化構建,構建後的結果作為一個提供服務者返回,其對應的類型為 ServiceProvider;最後,如果獲取某個已經註冊的服務的話,可以通過 serviceProvider.GetService() 來獲取。

下麵,我分別從下麵 4 個方面來體驗一下 DotNet Core 中強大的 DI

註入並設置服務的生命周期

註冊服務需要涉及到服務的生命周期,因此,IServiceCollection 有 3 個不同的擴展方法:

  • AddTransient:每次獲取的服務都是新創建的;
  • AddScoped:在一定範圍內獲取的服務是同一個;
  • AddSingleton:每次獲取的服務都是同一個,單例模式的服務;

示例代碼如下所示:

public interface IBaseSender
{
    void Send(string message);

}

public interface ITransientSender : IBaseSender { }
public class TransientSender : ITransientSender
{
    public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
}

public interface IScopedSender : IBaseSender { }
public class ScopedSender : IScopedSender
{
    public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
}

public interface ISingletonSender : IBaseSender { }
public class SingletonSender : ISingletonSender
{
    public void Send(string message) => Console.WriteLine($"{GetHashCode()} {message}");
}

class Program
{
    private static readonly object locker = new object();
    static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddTransient<ITransientSender, TransientSender>()
            .AddScoped<IScopedSender,ScopedSender>()
            .AddSingleton<ISingletonSender, SingletonSender>()
            .BuildServiceProvider();

        using (var scope = serviceProvider.CreateScope())
        {
            for (int i = 0; i < 2; i++)
            {
                serviceProvider.GetService<ITransientSender>().Send("ITransientSender");
                scope.ServiceProvider.GetService<IScopedSender>().Send("IScopedSender");
                serviceProvider.GetService<ISingletonSender>().Send("ISingletonSender");
            }
        }
        Console.WriteLine("***********************************");
        using (var scope = serviceProvider.CreateScope())
        {
            for (int i = 0; i < 2; i++)
            {
                serviceProvider.GetService<ITransientSender>().Send("ITransientSender");
                scope.ServiceProvider.GetService<IScopedSender>().Send("IScopedSender");
                serviceProvider.GetService<ISingletonSender>().Send("ISingletonSender");
            }
        }

        Console.ReadKey();
    }
}

程式輸出如下圖所示:


通過上圖我們可以瞭解到,

  • 在相同或不同的作用域內,通過 AddTransient 註冊的服務每次都是新創建的;
  • 在相同作用域內,通過 AddScoped 註冊的服務每次同一個;在不同請求作用域中,通過 AddScoped 註冊的服務每次都是新創建的;
  • 通過 AddSingleton 註冊的服務在整個程式生命周期內是同一個;

需要註意的是,在 ASP.NET Core 中,所有與 EF 相關的服務都應該通過 AddScoped<TInterface,T> 的方式註入。此外,如果想註入泛型的話,可藉助 typeof方式來註入。

構造函數註入

參數註入

public interface IBaseSender
{
    void Send();
}

public class EmialSender : IBaseSender
{
    private readonly string _msg;
    public EmialSender(string msg) => _msg = msg;

    public void Send() => Console.WriteLine($"{_msg}");
}

class Program
{
    static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<IBaseSender, EmialSender>(factory => { return new EmialSender("Hello World"); })
            .BuildServiceProvider();

        serviceProvider.GetService<IBaseSender>().Send();

        Console.ReadKey();
    }
}

服務註入

public interface IBaseSender
{
    void Send();
}

public class EmialSender : IBaseSender
{
    private readonly IWorker _worker;
    public EmialSender(IWorker worker) => _worker = worker;

    public void Send() =>_worker.Run("Hello World");
}

public interface IWorker
{
    void Run(string message);
}

public class Worker : IWorker
{
    public void Run(string message)
    {
        Console.WriteLine(message);
    }
}

class Program
{
    private static readonly object locker = new object();
    static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<IBaseSender, EmialSender>()
            .AddSingleton<IWorker, Worker>()
            .BuildServiceProvider();

        serviceProvider.GetService<IBaseSender>().Send();

        Console.ReadKey();
    }
}

在傳統的DotNet 框架下開發,註入是支持 參數、服務和屬性的,但是在 DotNet Core 平臺下目前只支持前兩種註入方式。

添加日誌記錄

DotNet Core 中已經將 Logger 功能集成進來,只需要安裝相應的 Package 即可食用。

Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console
Microsoft.Extensions.Logging.Debug

示常式序如下所示:

public interface IBaseSender
{
    void Send();
}

public class EmialSender : IBaseSender
{
    private readonly IWorker _worker;
    private readonly ILogger<EmialSender> _logger;

    public EmialSender(IWorker worker, ILogger<EmialSender> logger)
    {
        _worker = worker;
        _logger = logger;
    }

    public void Send()
    {
        _worker.Run("Hello World");
        _logger.LogInformation(MethodBase.GetCurrentMethod().Name);
    }
}

public interface IWorker
{
    void Run(string message);
}

public class Worker : IWorker
{
    public void Run(string message)
    {
        Console.WriteLine(message);
    }
}

class Program
{
    private static readonly object locker = new object();
    static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<IBaseSender, EmialSender>()
            .AddSingleton<IWorker, Worker>()
            .AddSingleton(new LoggerFactory().AddConsole().AddDebug())
            .AddLogging()
            .BuildServiceProvider();

        serviceProvider.GetService<IBaseSender>().Send();

        Console.ReadKey();
    }
}

總結

這次做的幾個小實驗還是很有趣的,體驗了一下 DotNet Core 中強大的 DI 功能。和傳統的 DotNet Framework 相比,有很多改進的地方,這是值得每一個 DotNet 程式員 去嘗試的一門新技術。

相關參考


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

-Advertisement-
Play Games
更多相關文章
  • 使用NPOI導入Excel 首先在MVC項目中導入NPOI 查詢NPOI安裝,排序依據,選擇:最高下載量,選擇第一個。 在控制器中創建ExcelController 在Index視圖中寫入代碼: @using (Html.BeginForm("Import", "Excel", FormMethod ...
  • 有些場景下,需要隔離不同的DB,彼此DB之間不能互相訪問,但實際的業務場景又需要從A DB訪問B DB的情形,這時怎麼辦?我認為有如下常規的三種方案: 1.雙方提供RESET API,需要訪問不同DB數據時,可以通過API來獲取指定數據; 這種方案優點是隔離性、定製性強,統一齣入口,只能通過指定的A ...
  • 做項目時偶爾B類賦值給A類,碰巧A和B類型很多屬性欄位名是一樣的,或者只是大小寫不一樣,這是可以利用泛型,反射來寫一個自動化賦值的方法。 下麵方法不考慮大小寫不一樣的情況,如果要考慮,可以使用字元串方法 ToUpper() 、ToLower() 後,對比欄位名是否一樣。 值得註意的地方,屬性到底有沒 ...
  • 前言 今年是2018年,發現已經有4年沒有寫博客了,在這4年的時光里,接觸了很多的.NET技術,自己的技術也得到很大的進步。在這段時光裡面很感謝張隊長以及其他開發者一直對.NET Core開源社區做出的巨大貢獻,我也在其中學習到很多的知識,因此在這段時間我也開始記錄我的學習成果,供大家好好學習,以及 ...
  • 生成代理類步驟: 一:找到Visual Studio 的工具文件夾 二:用管理員方式打開本機工具命令提示 三:輸入要執行的腳本 wsdl /language:C# /n:xxxx.HermesMobileWebService /out:C:\BaServiceClient.cs http://hb- ...
  • 好吧,我又回來了,其實一直都想寫一篇關於EF core 的文章去記錄自己在開發時候遇到的問題。 EF core 就是字面上的意思咯,EF 就是.Net上用的很多的ORM框架,core呢,就是在.Net core 上使用的EF咯。 為什麼要使用EF框架呢,因為原始的ADO.NET需要編寫大量的數據訪問 ...
  • 插入排序,是迴圈遍歷一個無序數組(例如有10個元素),把遍歷出來的數值(第i個元素)插入到已經排過順序的數組(這個有序數組有10-i個元素)中。 用一個 數組 舉個例子: 初始數組:1, 89, 4, 34, 56, 40, 59, 60, 39, 1, 40, 90, 48 第一次迴圈(i=0): ...
  • 最近公司需要在伺服器上實現兩個音頻的合成及效果處理。 哇,乍一聽功能很簡單吧,就是將兩個音頻疊加,隨便一個媒體處理軟體幾秒鐘即可完成,但這僅僅只是針對單用戶而言而已。其次,本來這種服務原本就不應該在伺服器上面實現,為何? 流媒體處理是相當耗費伺服器資源的,包括IO,CPU,bandwidth等等。 ...
一周排行
    -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 ...