我正在为一个奇怪的案件而苦苦挣扎。我有一个.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);
我想念什么?
答案 0 :(得分:1)
将您的注册更改为以下内容:
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>();
从简单的字典映射到服务类型(IGatewayServer
或实现(分别为Server1
或Server2
)的MS.DI中的注册。当您请求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
使用者中(但请确保validation is enabled)。如果您将其注册为Transient
,则该委托将被注入Singleton
使用者中,但是当请求的服务依赖于{{1 }}的生活方式,因为这会导致Captive Dependencies。否则,当您解决实现GetRequiredService
的{{1}}组件时,甚至可能导致内存泄漏(真糟糕!)。但是,将委托注册为Scoped
也会导致专属依赖性产生相同的问题。因此,Transient
是唯一明智的选择。
代替返回IDisposable
来获取未知的Singleton
:
Scoped
我抛出异常,使应用程序快速失败:
null