aspnetcore 原生 DI 實現基於 key 的服務獲取

你可能想通過一個字符串或者其他的類型來獲取一個具體的服務實現,那麼在 aspnetcore 原生的 MSDI 中,如何實現呢?本文將介紹如何通過自定義工廠來實現。

我們現在恰好有基於 Json 和 MessagePack 的兩種序列化器

有一個接口是這樣的

public interface ISerializer
{
    byte[] Serialize<T>(T obj);
    T Deserialize<T>(ReadOnlySpan<byte> data);
}

並且由兩個不同的實現

// Json
public class MyJsonSerializer : ISerializer
{
    public byte[] Serialize<T>(T obj)
    {
        throw new NotImplementedException();
    }

    public T Deserialize<T>(ReadOnlySpan<byte> data)
    {
        throw new NotImplementedException();
    }
}

// MessagePack
public class MyMessagePackSerializer : ISerializer
{
    public byte[] Serialize<T>(T obj)
    {
        throw new NotImplementedException();
    }

    public T Deserialize<T>(ReadOnlySpan<byte> data)
    {
        throw new NotImplementedException();
    }
}

我有一個服務,需要使用這兩種序列化器中的一種。

public class MyService
{
    public object DoSomething(string dataType, ReadOnlySpan<byte> data)
    {
        // 根據 dataType 來決定使用哪種序列化器
    }
}

使用委託來定義獲取服務的方法

我們可以通過委託來定義獲取服務的方法,如下

public delegate ISerializer SerializerFactory(string dataType);

然後在 ConfigureServices 方法中註冊

services.AddSingleton<MyJsonSerializer>();
services.AddSingleton<MyMessagePackSerializer>();
services.AddSingleton<SerializerFactory>(sp =>
{
    return dataType =>
    {
        switch (dataType)
        {
            case "json":
                return sp.GetRequiredService<MyJsonSerializer>();
            case "msgpack":
                return sp.GetRequiredService<MyMessagePackSerializer>();
            default:
                throw new NotSupportedException();
        }
    };
});

這樣我們就可以在 MyService 中通過委託來獲取服務了

public class MyService
{
    private readonly SerializerFactory _serializerFactory;

    public MyService(SerializerFactory serializerFactory)
    {
        _serializerFactory = serializerFactory;
    }

    public object DoSomething(string dataType, ReadOnlySpan<byte> data)
    {
        var serializer = _serializerFactory(dataType);
        return serializer.Deserialize<object>(data);
    }
}

基於配置來改變工廠

因爲本質是通過委託來獲取服務,所以我們可以通過配置來改變委託的行爲,如下

public static class SerializerFactoryExtensions
{
    public static SerializerFactory CreateSerializerFactory(this IServiceProvider sp)
    {
        // get mapping from configuration
        var mapping = sp.GetRequiredService<IConfiguration>()
                      .GetSection("SerializerMapping")
                      .Get<Dictionary<string, string>>();
        return dataType =>
        {
            var serializerType = mapping[dataType];
            return (ISerializer)sp.GetRequiredService(Type.GetType(serializerType));
        };
    }
}

然後在 appsettings.json 中配置

{
  "SerializerMapping": {
    "json": "WebApplication1.MyJsonSerializer",
    "msgpack": "WebApplication1.MyMessagePackSerializer"
  }
}

然後在 ConfigureServices 方法中註冊

services.AddSingleton<MyJsonSerializer>();
services.AddSingleton<MyMessagePackSerializer>();
services.AddSingleton(SerializerFactoryExtensions.CreateSerializerFactory);

總結

本篇文章介紹瞭如何通過自定義工廠來實現基於 key 的服務獲取,這種方式在 aspnetcore 原生的 DI 中是原生支持的。

參考

感謝閱讀,如果覺得本文有用,不妨點擊推薦👍或者在評論區留下 Mark,讓更多的人可以看到。

歡迎關注作者的微信公衆號“newbe技術專欄”,獲取更多技術內容。 關注微信公衆號“newbe技術專欄”


  1. https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines?WT.mc_id=DX-MVP-5003606

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章