亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

.NET Core DI 使用自定義委托解析鍵控服務返回 null

.NET Core DI 使用自定義委托解析鍵控服務返回 null

C#
三國紛爭 2022-11-22 16:42:50
我正在為一個奇怪的案例而苦苦掙扎。我有一個 .NET Core 控制臺應用程序,其設置如下:private static async Task Main(string[] args){    var runAsService = !(Debugger.IsAttached || args.Contains("console"));    var builder = new HostBuilder()        .ConfigureServices((hostContext, services) =>        {            services.AddLogging(loggingBuilder => { loggingBuilder.AddConsole(); });            services.AddGatewayServers();            services.AddHostedService<GatewayService>();        });    if (runAsService)        await builder.RunServiceAsync();    else        await builder.RunConsoleAsync();}然后我對IServiceCollection這個設置進行了擴展,AddGatewayServers()如下所示:public static void AddGatewayServers(this IServiceCollection services){    services.AddTransient<IGatewayServer, Server1>();    services.AddTransient<IGatewayServer, Server2>();    services.AddTransient<Func<ServerType, IGatewayServer>>(provider => key =>    {        switch (key)        {            case ServerType.Type1: return provider.GetService<Server1>();            case ServerType.Type2: return provider.GetService<Server2>();            default: return null;        }    });}然后在我的課上我注入這樣的依賴:private readonly Func<ServerType, IGatewayServer> _gatewayAccessor;public GatewayServerCollection(Func<ServerType, IGatewayServer> gatewayAccessor){    _gatewayAccessor = gatewayAccessor;}但是當我_gatewayAccessor稍后調用它GatewayServerCollection來獲取它的實例時,IGatewayServer它會返回null。我這樣稱呼它:var server = _gatewayAccessor(ServerType.Type1);我錯過了什么?
查看完整描述

1 回答

?
aluckdog

TA貢獻1847條經驗 獲得超7個贊

將您的注冊更改為以下內容:


public static void AddGatewayServers(this IServiceCollection services)

{

    services.AddTransient<Server1>();

    services.AddTransient<Server2>();

    services.AddScoped<Func<ServerType, IGatewayServer>>(provider => (key) =>

    {

        switch (key)

        {

            case ServerType.Type1: return provider.GetRequiredService<Server1>();

            case ServerType.Type2: return provider.GetRequiredService<Server2>();

            default: throw new InvalidEnumArgumentException(

                typeof(ServerType), (int)key, nameof(key));

        }

    });

}

最重要的變化來自于:


services.AddTransient<IGatewayServer, Server1>();

services.AddTransient<IGatewayServer, Server2>();

對此:


services.AddTransient<Server1>();

services.AddTransient<Server2>();

MS.DI 中的注冊來自從服務類型 ( IGatewayServer) 到實現(Server1或Server2分別)的簡單字典映射。當你請求時,它在它的字典中Server1找不到。typeof(Server1)因此,解決方案是按具體類型注冊這些類型。


最重要的是,我使用了以下GetRequiredService方法:


provider.GetRequiredService<Server1>()

而不是GetService:


provider.GetService<Server1>()

GetRequiredService當注冊不存在時將拋出異常,這允許您的代碼快速失敗。


我更改了代表的注冊Transient:


services.AddTransient<Func<ServerType, IGatewayServer>>

到Scoped:


services.AddScoped<Func<ServerType, IGatewayServer>>

這可以防止它被注入到任何Singleton消費者中,因為 MS.DI 只能防止Scoped服務被注入到Singleton消費者中,但不會阻止Transient實例被注入到Scoped消費者中Singleton(但請確保啟用驗證)。如果您將其注冊為Transient,委托將被注入到消費者中,但是當您調用所請求的服務取決于生活方式Singleton時,這最終會在運行時失敗,因為這會導致Captive Dependencies?;蛘咚踔量赡軐е聝却嫘孤?,當您解析實現的組件時(糟糕?。?。將代表注冊為GetRequiredServiceScopedTransientIDisposableSingleton,但是,也會導致與俘虜依賴項相同的問題。所以Scoped是唯一明智的選擇。


而不是返回null一個未知數ServerType:


default:

    return null;

我拋出一個異常,讓應用程序快速失?。?/p>


default:

    throw new InvalidEnumArgumentException(...);


查看完整回答
反對 回復 2022-11-22
  • 1 回答
  • 0 關注
  • 102 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號