如何在 .NET Web 中使用 BackgroundService 中的数据库 API
How to use the database from a BackgroundService in .NET Web API
我正在构建一个微服务,它应该通过各种方式发送定期通知。
为了处理通知和触发器,我打算使用一个 BackgroundService,它将查看数据库,根据通知类型调用适当的服务,并将通知标记到数据库中作为已发送。
如何以安全的方式从后台服务访问数据库,而不会出现并发问题?
注入 IServiceProvider 并创建作用域是否足够?
public class MyBackgroundService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public MyBackgroundService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
using (IServiceScope scope = _serviceProvider.CreateScope())
{
IRepository<Notification> notificationRepository =
scope.ServiceProvider.GetRequiredService<IRepository<Notification>>();
IRepository<NotificationLog> notificationLogRepository =
scope.ServiceProvider.GetRequiredService<IRepository<NotificationLog>>();
IUnitOfWork unitOfWork =
scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
while(true)
{
if(stoppingToken.IsCancellationRequested)
{
return;
}
var list = await notificationRepository.GetAll();
.....................................
await notificationLogRepository.Add(...);
await unitOfWork.Commit();
}
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
await base.StopAsync(stoppingToken);
}
}
Is it enough to inject IServiceProvider and create a scope?
是的。
虽然您可以为整个后台工作人员的生命周期创建一个范围,但您也可以为每个“调用”创建一个范围 - 在这种情况下,您可以创建一个新范围每次定时器响起。这样,如果出现下一个调用在当前调用完成之前开始的情况,将保证这两个调用具有不同的范围。
但是,如果您的“计时器”只是在执行 await Task.Delay
,那么就不可能出现重叠调用,并且不需要单独的范围。无论如何,有些人更喜欢它们,因为“调用”和“范围”在概念上可以很好地结合在一起。
我正在构建一个微服务,它应该通过各种方式发送定期通知。
为了处理通知和触发器,我打算使用一个 BackgroundService,它将查看数据库,根据通知类型调用适当的服务,并将通知标记到数据库中作为已发送。
如何以安全的方式从后台服务访问数据库,而不会出现并发问题?
注入 IServiceProvider 并创建作用域是否足够?
public class MyBackgroundService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public MyBackgroundService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
using (IServiceScope scope = _serviceProvider.CreateScope())
{
IRepository<Notification> notificationRepository =
scope.ServiceProvider.GetRequiredService<IRepository<Notification>>();
IRepository<NotificationLog> notificationLogRepository =
scope.ServiceProvider.GetRequiredService<IRepository<NotificationLog>>();
IUnitOfWork unitOfWork =
scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
while(true)
{
if(stoppingToken.IsCancellationRequested)
{
return;
}
var list = await notificationRepository.GetAll();
.....................................
await notificationLogRepository.Add(...);
await unitOfWork.Commit();
}
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
await base.StopAsync(stoppingToken);
}
}
Is it enough to inject IServiceProvider and create a scope?
是的。
虽然您可以为整个后台工作人员的生命周期创建一个范围,但您也可以为每个“调用”创建一个范围 - 在这种情况下,您可以创建一个新范围每次定时器响起。这样,如果出现下一个调用在当前调用完成之前开始的情况,将保证这两个调用具有不同的范围。
但是,如果您的“计时器”只是在执行 await Task.Delay
,那么就不可能出现重叠调用,并且不需要单独的范围。无论如何,有些人更喜欢它们,因为“调用”和“范围”在概念上可以很好地结合在一起。