依賴注入

2022-07-20 15:01:18

Masa的依賴注入系統是基於Microsoft的依賴注入擴充套件庫(Microsoft.Extensions.DependencyInjection nuget包)開發的,因此,它的檔案在Masa中也是有效的。

按照約定的註冊

Masa引入了按照約定進行服務註冊,依據約定大於設定,開發者無需做任何事,框架會自動完成註冊

依賴介面

  • ISingletonDependency: 註冊生命週期為Singleton的服務
  • IScopedDependency: 註冊生命週期為Scoped的服務
  • ITransientDependency: 註冊生命週期為Transient的服務
  • IAutoFireDependency: 自動觸發(與ISingletonDependency、IScopedDependency、ITransientDependency結合使用,在服務自動註冊結束後觸發一次獲取服務操作,僅繼承IAutoFireDependency不起作用)

範例:

``` C#
public class StorageOptions : ITransientDependency
{
  
}
```

特性

IgnoreInjection

忽略注入,用於排除不被自動注入

  • Cascade: 設定為true時,當前類以及子類都不再被自動註冊,設定為false,僅當前類不被自動註冊(預設false)

範例:

``` C#
public class BaseService : ISingletonDependency
{
    public static int Count { get; set; } = 0;

    public BaseService()
    {
        Count++;
    }

    public BaseService(bool isChildren)
    {

    }
}

[IgnoreInjection]
public class GoodsBaseService : BaseService
{
    public GoodsBaseService() : base(true)
    {
    }
}

public class GoodsService : GoodsBaseService
{
    public static int GoodsCount { get; set; } = 0;

    public GoodsService()
    {
        GoodsCount++;
    }
}
```

效果等同於:services.AddSingleton<BaseService>(); services.AddSingleton<GoodsService>();

Dependency

配合ISingletonDependency、IScopedDependency、ITransientDependency使用,實現服務僅被註冊一次

  • TryRegister: 設定true則僅當服務未註冊時才會被註冊,類似IServiceCollection的TryAdd ... 擴充套件方法.

範例:

``` C#
public interface ICache : ISingletonDependency
{
    void Set(string key, string value);
}

[Dependency(TryRegister = true)]
public class EmptyCache : ICache
{
    public void Set(string key, string value)
    {
        throw new NotSupportedException($"暫不支援{nameof(Set)}方法");
    }
}

public class MemoryCache : ICache
{
    private readonly ConcurrentDictionary<string, Lazy<string>> _dicCache = new();

    public void Set(string key, string value)
    {
        _ = _dicCache.AddOrUpdate
        (
            key,
            k => new Lazy<string>(() => value, LazyThreadSafetyMode.ExecutionAndPublication),
            (_, _) => new Lazy<string>(() => value, LazyThreadSafetyMode.ExecutionAndPublication)
        ).Value;
    }
}
```

效果等同於:services.AddSingleton<ICache, MemoryCache>();

  • ReplaceServices: 設定true則替換之前已經註冊過的服務,類似IServiceCollection的Replace ... 擴充套件方法.

範例:

``` C#
public interface IEncryptionService : ISingletonDependency
{
    string MethodName { get; }
}

[Dependency(ReplaceServices = true)]
public class Sha1EncryptionService : IEncryptionService
{
    public string MethodName => "Sha1";
}

public class Md5EncryptionService : IEncryptionService
{
    public string MethodName => "Md5";
}
```

效果等同於:services.AddSingleton<IEncryptionService, Sha1EncryptionService>();

快速入門

  1. 新建單元測試專案Assignment.DependencyInjection,選擇MSTest,並安裝Masa.Utils.Extensions.DependencyInjection

    dotnet new xunit -o Assignment.DependencyInjection
    cd Assignment.DependencyInjection
    dotnet add package Masa.Utils.Extensions.DependencyInjection --version 0.5.0-preview.2
    
  2. 新建類StorageOptions

    public class StorageOptions : ITransientDependency
    {
      
    }
    
  3. 新建類DITest

    [TestClass]
    public class DITest
    {
        private IServiceCollection _services;
    
        [TestInitialize]
        public void Init()
        {
            _services = new ServiceCollection();
            _services.AddAutoInject();//執行自動注入
        }
    
        [TestMethod]
        public void TestAutoInject()
        {
            Assert.IsTrue(_services.Any<StorageOptions>(ServiceLifetime.Transient));//判斷StorageOptions註冊成功,且生命週期為Transient
        }
    
        private IServiceProvider ServiceProvider => _services.BuildServiceProvider();
    }
    

總結

如果需要使用按照約定自動註冊服務,則請記住

  • 根據業務需要,則指定類或介面中實現以下介面
    • ISingletonDependency 單例(專案啟動後僅初始化一次)
    • IScopedDependency 請求 (每次請求僅初始化一次)
    • ITransientDependency 瞬時(每次獲取都會被初始化)
  • 抽象類不會被自動註冊
  • 如果你有一個自定義介面IRepository,且希望介面以及對應的預設實現類RepositoryBase會被自動註冊生命週期為Scoped,則介面IRepository應該繼承IScopedDependency
    • 如果你希望預設提供的RepositoryBase可以被使用者定義的類替換,則應該在RepositoryBase上方增加[Dependency(TryRegister = true)],那使用者僅需要實現IRepository即可
    • 或不更改預設提供的RepositoryBase,使用者實現IRepository後,並在新的實現類上方增加[Dependency(ReplaceServices = true)]

本章原始碼

Assignment07

https://github.com/zhenlei520/MasaFramework.Practice

開源地址

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks

MASA.Contrib:https://github.com/masastack/MASA.Contrib

MASA.Utils:https://github.com/masastack/MASA.Utils

MASA.EShop:https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

如果你對我們的 MASA Framework 感興趣,無論是程式碼貢獻、使用、提 Issue,歡迎聯絡我們