GTH*_*ten 5 c# dependency-injection .net-core
在 C#.NET Core 中,您可以使用以下代码创建通用主机:
IHostBuilder builder = new HostBuilder()
.ConfigureServices((context, collection) => {
collection.AddSingleton<IMyClass, MyClass>();
collection.AddHostedService<MyService>();
});
await builder.RunConsoleAsync();
Run Code Online (Sandbox Code Playgroud)
MyService这将使用默认 DI 容器创建一个新实例。
现在,假设我想在 内部创建一个新主机MyService。这很简单(在本例中是网络主机):
IWebHost webHost = WebHost.CreateDefaultBuilder()
.UseStartup<MyStartup>()
.Build();
.RunAsync();
Run Code Online (Sandbox Code Playgroud)
该 Web 主机将拥有自己的依赖项注入容器,因此它将无法访问我已添加到通用主机容器中的所有依赖项:即,它将无法注入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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的中,HostBuilder我通过添加了它.UseServiceProviderFactory(new CustomServiceProviderFactory(_serviceProvider)),但由于某种原因,HostedService在创建它之前实例化了它,导致 DI 异常关于找不到所需的对象。
然而,现在看来 asWebHost.CreateDefaultBuilder()是创建 Web 主机的首选方式(在 .NET Core 3.0 中),并且IWebHostBuilder没有设置自定义的选项IServiceProviderFactory,这似乎是一个死胡同。
如何让 Web 主机使用与初始通用主机相同的 DI 容器?
我也尝试过做同样的事情,这就是我所实现的。尚未完全测试,但它似乎确实有效。
首先,在我的 base/first 中HostBuilder,将服务集合添加为服务,以便IServiceCollection稍后可以通过 DI 进行解析。
IHostBuilder builder = new HostBuilder()
.ConfigureServices((ctx, services) =>
{
services.AddSingleton<IMyService, MyService>();
services.AddHostedService<MyApp>();
services.AddSingleton(services);
});
Run Code Online (Sandbox Code Playgroud)
在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();
Run Code Online (Sandbox Code Playgroud)
在 my 的构造函数中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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以Controller在添加后创建一个app.UseRouting()并app.UseEndpoints(...)在我的启动类中。注入IMyService已成功解决,可以正常使用了。
app.ApplicationServices.GetRequiredService<IMyService>()您还可以通过添加方法来测试它Startup.Configure(),并查看是否返回了正确的服务。
| 归档时间: |
|
| 查看次数: |
1270 次 |
| 最近记录: |