我正在尝试创建一个执行 Sql 命令的计划任务。实际计划的过程工作正常,但是我的 dbcontext 存在无法实际访问数据库的问题。
它将获得一个包含所有适当表的上下文,但对表的任何操作都会引发InvalidOperationException
. 当尝试在调试模式下检查任何表格元素时,它们也都InvalidOperationException
以红色X
作为图标。
我也尝试通过MediatR
命令和处理程序发送命令,但错误相同。每次更改代码的尝试都会导致相同的错误而没有偏差。
这是我第一次尝试创建后台服务,作为参考,我正在学习 https://thinkrethink.net/2018/02/21/asp-net-core-background-processing/的教程
启动.cs
// truncated
services.AddDbContext<MyDbContext>();
services.AddSingleton<IHostedService, Daily_Task>();
后台服务
namespace MyApi.ScheduledTasks
{
public abstract class BackgroundService : IHostedService
{
private Task _executingTask;
private readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
public virtual Task StartAsync(CancellationToken token)
{
_executingTask = ExecuteAsync(tokenSource.Token);
return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken token)
{
if (_executingTask == null)
return;
try
{
tokenSource.Cancel();
}
finally
{
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, token));
}
}
protected virtual async Task ExecuteAsync(CancellationToken token)
{
do
await Process();
while (!token.IsCancellationRequested);
}
protected abstract Task Process();
}
}
范围处理器
namespace MyApi.ScheduledTasks
{
public abstract class ScopedProcessor: BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
public ScopedProcessor(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected override async Task Process()
{
using (var scope = _scopeFactory.CreateScope())
{
await ProcessInScope(scope.ServiceProvider);
}
}
public abstract Task ProcessInScope(IServiceProvider provider);
}
}
待安排的任务
namespace MyApi.ScheduledTasks
{
public class Daily_Task : ScopedProcessor
{
private DateTime Start => DateTime.Now;
private DateTime NextTask { get; private set; }
public Daily_Task(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
NextTask = SetNextRun(Start);
}
// currently doing minutes for testing
private DateTime SetNextRun(DateTime date) => date.AddMinutes(1);
public override async Task ProcessInScope(IServiceProvider provider)
{
try
{
using (var context = provider.GetRequiredService<MyDbContext>())
{
// even this causes an error
var data = context.MyTable.Any();
}
}
catch (Exception e)
{
Log.Error(e);
}
await Task.CompletedTask;
}
protected override async Task ExecuteAsync(CancellationToken token)
{
do
{
var now = DateTime.Now;
if (now > NextTask)
{
await Process();
NextTask = SetNextRun(now);
}
}
while (!token.IsCancellationRequested);
}
}
}