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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...