在应用程序启动时从 IHostedService 异步更新 autofac 容器
Update autofac container from IHostedService asynchronously on app startup
我有一个 ASP.net 核心 3.0 应用程序,我想看看我是否可以在应用程序启动时异步注册我的一些 Orleans Cluster 客户端,因为创建并连接到 Orleans Cluster很重。根据这个 article I created my own IHostedService, but when I implemented startAsync method I am not sure how to get the autofac container which I am using in Startup.cs and update it with my clients registrations. I have read this 但是看我下面的代码,我仍然没有看到客户正在注册。这是可行的还是我在这里遗漏了什么?谢谢!
Startup.cs
...
public static IServiceProvider ConfigureServices(IServiceCollection services)
{
var coreBuilder = new ContainerBuilder();
// other autofac registrations...
services.AddHostedService<MyService>();
coreBuilder.populate(services);
var container = coreBuilder.Build();
var serviceProvider = new AutofacServiceProvider(container);
return serviceProvider;
}
MyService.cs
public MyService : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// get the autofac container from Startup.cs and update with cluster client registrations?
using(var scope = this._serviceProvider.GetRequiredService<ILifeTimeScope>()
.BeginLifeTimeScope(builder => do registration here...)) {}
}
// noop
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
你不能像那样即时更新 DI 容器。建好了就建好了。
您还有另一种选择:创建一个缓存客户端的工厂 class,在后台初始化它们,然后从工厂中检索它们。
class MyService
{
// ...
}
class MyServiceFactory
{
private ConcurrentDictionary<string, MyService> _instances = new ConcurrentDictionary<string, MyService>();
public async Task<MyService> CreateAsync(string key)
{
if (_instances.TryGetValue(key, out var service))
{
return service;
}
// perform expensive initialization
// ...
service = new MyService();
_instances[key] = service;
return service;
}
}
class MyServiceInitializer: BackgroundService
{
private MyServiceFactory _serviceFactory;
public MyServiceInitializer(MyServiceFactory serviceFactory)
{
_serviceFactory = serviceFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _serviceFactory.CreateAsync("first instance");
await _serviceFactory.CreateAsync("second instance");
}
}
将工厂注册为单例,(或使Instances
成为static
属性)。
services.AddSingleton<MyServiceFactory>();
services.AddHostedService<MyServiceInitializer>();
然后解析一个你需要的实例。它会立即解析,因为它已在后台初始化。
class MyController
{
private MyServiceFactory _serviceFactory;
public MyController(MyServiceFactory serviceFactory)
{
_serviceFactory = serviceFactory;
}
[HttpGet]
public async Task<ActionResult> Index()
{
var service = await _serviceFactory.CreateAsync("first instance");
// use the service
}
}
我有一个 ASP.net 核心 3.0 应用程序,我想看看我是否可以在应用程序启动时异步注册我的一些 Orleans Cluster 客户端,因为创建并连接到 Orleans Cluster很重。根据这个 article I created my own IHostedService, but when I implemented startAsync method I am not sure how to get the autofac container which I am using in Startup.cs and update it with my clients registrations. I have read this 但是看我下面的代码,我仍然没有看到客户正在注册。这是可行的还是我在这里遗漏了什么?谢谢!
Startup.cs
...
public static IServiceProvider ConfigureServices(IServiceCollection services)
{
var coreBuilder = new ContainerBuilder();
// other autofac registrations...
services.AddHostedService<MyService>();
coreBuilder.populate(services);
var container = coreBuilder.Build();
var serviceProvider = new AutofacServiceProvider(container);
return serviceProvider;
}
MyService.cs
public MyService : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// get the autofac container from Startup.cs and update with cluster client registrations?
using(var scope = this._serviceProvider.GetRequiredService<ILifeTimeScope>()
.BeginLifeTimeScope(builder => do registration here...)) {}
}
// noop
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
你不能像那样即时更新 DI 容器。建好了就建好了。
您还有另一种选择:创建一个缓存客户端的工厂 class,在后台初始化它们,然后从工厂中检索它们。
class MyService
{
// ...
}
class MyServiceFactory
{
private ConcurrentDictionary<string, MyService> _instances = new ConcurrentDictionary<string, MyService>();
public async Task<MyService> CreateAsync(string key)
{
if (_instances.TryGetValue(key, out var service))
{
return service;
}
// perform expensive initialization
// ...
service = new MyService();
_instances[key] = service;
return service;
}
}
class MyServiceInitializer: BackgroundService
{
private MyServiceFactory _serviceFactory;
public MyServiceInitializer(MyServiceFactory serviceFactory)
{
_serviceFactory = serviceFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _serviceFactory.CreateAsync("first instance");
await _serviceFactory.CreateAsync("second instance");
}
}
将工厂注册为单例,(或使Instances
成为static
属性)。
services.AddSingleton<MyServiceFactory>();
services.AddHostedService<MyServiceInitializer>();
然后解析一个你需要的实例。它会立即解析,因为它已在后台初始化。
class MyController
{
private MyServiceFactory _serviceFactory;
public MyController(MyServiceFactory serviceFactory)
{
_serviceFactory = serviceFactory;
}
[HttpGet]
public async Task<ActionResult> Index()
{
var service = await _serviceFactory.CreateAsync("first instance");
// use the service
}
}