gpt4 book ai didi

c# - 具有相同 DI 容器的多个主机

转载 作者:行者123 更新时间:2023-12-05 07:19:33 25 4
gpt4 key购买 nike

在 C#.NET Core 中,您可以使用以下代码创建通用主机:

IHostBuilder builder = new HostBuilder()
.ConfigureServices((context, collection) => {
collection.AddSingleton<IMyClass, MyClass>();
collection.AddHostedService<MyService>();
});
await builder.RunConsoleAsync();

这会使用默认的 DI 容器创建一个 MyService 的新实例。

现在,假设我想在 MyService 中创建一个新主机。这很容易(在这种情况下是网络主机):

IWebHost webHost = WebHost.CreateDefaultBuilder()
.UseStartup<MyStartup>()
.Build();
.RunAsync();

此 webhost 将有自己的依赖注入(inject)容器,因此它不能访问我已经添加到通用主机容器的所有依赖项:即它不能注入(inject) IMyClass进入 MyStartup

我还尝试使用以下代码添加自定义 IServiceProviderFactory<>(基于他们使用 .UseDefaultServiceProvider() 作为构建器类型的 IServiceCollection 代码):

public class CustomServiceProviderFactory :  IServiceProviderFactory<IServiceCollection>
{
private readonly IServiceProvider _provider;

public CustomServiceProviderFactory(IServiceProvider provider)
{
_provider = provider;
}

public IServiceCollection CreateBuilder(IServiceCollection services)
{
return services;
}

public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
return _provider;
}
}

然后在我的 HostBuilder 中,我通过 .UseServiceProviderFactory(new CustomServiceProviderFactory(_serviceProvider)) 添加了它,但由于某种原因,HostedService 在创建之前被实例化,导致 DI 异常,找不到所需的对象。

但是,现在 WebHost.CreateDefaultBuilder() 是创建虚拟主机 (in .NET Core 3.0) 的首选方式,而 IWebHostBuilder 没有设置自定义 IServiceProviderFactory 的选项,这似乎是死胡同。

如何让虚拟主机使用与初始通用主机相同的 DI 容器?

最佳答案

我尝试过做同样的事情,这就是我的目标。未经过全面测试,但似乎确实有效。

首先,在我的基地/第一个HostBuilder ,将服务集合添加为服务,这样 IServiceCollection稍后可以通过 DI 解决。

IHostBuilder builder = new HostBuilder()
.ConfigureServices((ctx, services) =>
{
services.AddSingleton<IMyService, MyService>();
services.AddHostedService<MyApp>();
services.AddSingleton(services);
});

IHostedService.StartAsync()我创建了 WebHost。我复制了 services.Replace 的用法来自内部的功能 UseDefaultServiceProvider() :

IWebHost host = WebHost
.CreateDefaultBuilder()
.ConfigureServices(services =>
{
var options = new ServiceProviderOptions();
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(new CustomServiceProviderFactory(_services, options)));
})
.UseStartup<MyStartup>()
.Build();

在我的 CustomServicesProvider 的构造函数中, 我还需要删除任何 IHostedService服务,否则您似乎进入了服务启动的无限循环。创建服务提供者时,我将构造函数传递的服务集合中的所有内容添加到本地服务集合中。

class CustomServiceProviderFactory : IServiceProviderFactory<IServiceCollection>
{
private readonly IServiceCollection _baseServices;
private readonly ServiceProviderOptions _options;

public CustomServiceProviderFactory(IServiceCollection baseServices, ServiceProviderOptions options)
{
_baseServices = baseServices;
_options = options;
_baseServices.RemoveAll<IHostedService>();
}

public IServiceCollection CreateBuilder(IServiceCollection services)
{
return services;
}

public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
foreach (var service in _baseServices)
{
containerBuilder.Add(service);
}

return containerBuilder.BuildServiceProvider(_options);
}
}

然后我能够创建一个 Controller添加 app.UseRouting() 后和 app.UseEndpoints(...)在我的创业课上。注入(inject) IMyService已成功解决,我可以正常使用它。

您也可以通过添加 app.ApplicationServices.GetRequiredService<IMyService>() 来测试它在你的Startup.Configure()方法并查看是否返回了正确的服务。

关于c# - 具有相同 DI 容器的多个主机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57731962/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com