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

背景敘述

在前面幾篇 MEF 插件式開發 系列博客中,我分別在 DotNet FrameworkDotNet Core 兩種框架下實驗了 MEF 的簡單實驗,因爲 DotNet Framework 由來已久,所以基於該框架下衍生出的不少優秀的 MEF 框架較多。可是對於 DotNet Core 來講,狀況有所不一樣,因爲它自己對 DI 內置並提供支持,所以我嘗試使用它的全新 依賴注入(DI) 來作一些實驗。html

動手實驗

要想讓程序支持 DI,就須要爲項目安裝 Package:程序員

Install-Package Microsoft.Extensions.DependencyInjection -Version 2.1.1

而後,咱們就可使用強大的 DI 了。c#

DotNet Core,全部服務的註冊都是統一放到一塊兒的,而這個就是由 ServiceCollection 來接收的;其次,當服務註冊完畢後,還須要對服務進行初始化構建,構建後的結果做爲一個提供服務者返回,其對應的類型爲 ServiceProvider;最後,若是獲取某個已經註冊的服務的話,能夠經過 serviceProvider.GetService () 來獲取。bash

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

注入並設置服務的生命週期

註冊服務須要涉及到服務的生命週期,所以,IServiceCollection 有 3 個不一樣的擴展方法:ide

  • 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();
    }
}

程序輸出以下圖所示:ui

經過上圖咱們能夠了解到,插件

  • 在相同或不一樣的做用域內,經過 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 程序員 去嘗試的一門新技術。

相關參考

相關文章
相關標籤/搜索