我为ASP.NET Core 2.1 Web App成功实现了后台任务,今天突然停止了工作,给我一个错误:
System.InvalidOperationException:无法使用作用域服务 单例的“ MyDbContext” “ Microsoft.Extensions.Hosting.IHostedService”
我知道关于该问题的话题很少,而且我已经阅读了有关此错误的内容,但我认为我的工作人员已正确实施。我正在创建范围服务,并且一直成功地工作到今天。 我的实现类似于本教程中的实现:https://shortly.cc/EIxe
背景任务代码:
public class OnlineTagger : Core.BackgroundService
{
private readonly CoordinatesHelper _coordinatesHelper;
public OnlineTagger(IServiceScopeFactory scopeFactory, CoordinatesHelper coordinatesHelper) : base(scopeFactory)
{
_coordinatesHelper = coordinatesHelper;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
Console.WriteLine("Online tagger Service is Running");
// Run something
await ProcessCoords(dbContext);
// Run every 30 sec
await Task.Delay(30000, stoppingToken);
}
}
}
private async Task ProcessCoords(MyDbContext dbContext)
{
var topCoords = await _coordinatesHelper.GetTopCoordinates();
foreach (var coord in topCoords)
{
var user = await dbContext.Users.SingleOrDefaultAsync(c => c.Id == coord.UserId);
if(user != null)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
//expire time = 120 sec
var coordTimeStamp = DateTimeOffset.FromUnixTimeMilliseconds(coord.TimeStamp).AddSeconds(120).ToUnixTimeMilliseconds();
if (coordTimeStamp < now && user.IsOnline == true)
{
user.IsOnline = false;
await dbContext.SaveChangesAsync();
}
else if(coordTimeStamp > now && user.IsOnline == false)
{
user.IsOnline = true;
await dbContext.SaveChangesAsync();
}
}
}
}
}
基类:
public abstract class BackgroundService : IHostedService, IDisposable
{
protected readonly IServiceScopeFactory _scopeFactory;
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource();
public BackgroundService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
Startup.cs:
services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, OnlineTagger>();