以干净的 AsyncLocal 状态启动任务

Start a task with clean AsyncLocal state

在 ASP.NET Core 中,我使用 IHttpContextAccessor 访问当前的 HttpContextHttpContextAccessor uses AsyncLocal<T>.

在一种情况下,我试图从请求中启动 Task,在请求结束后应该继续 运行(长 运行,后台任务),我正在尝试将其从当前执行上下文中分离出来,以便 IHttpContextAccessor returns null (否则我正在访问无效的 HttpContext)。

我尝试了 Task.RunThread.Start,但每次,上下文似乎都会延续,并且 IHttpContextAccessor returns 无论我尝试什么,旧的上下文(有时甚至是上下文来自其他请求)。

我怎样才能启动一个具有干净 AsyncLocal 状态的任务,以便 IHttpContextAccessor returns null?

您可以等待漫长的 运行ning 任务并在 await 中将 HttpContext 设置为 null 。对于任务之外的所有代码都是安全的。

[Fact]
public async Task AsyncLocalTest()
{
    _accessor = new HttpContextAccessor();

    _accessor.HttpContext = new DefaultHttpContext();

    await LongRunningTaskAsync();

    Assert.True(_accessor.HttpContext != null);
}

private async Task LongRunningTaskAsync()
{
    _accessor.HttpContext = null;
}

你可以运行一个单独的线程,没关系。

Task.Run(async () => await LongRunningTaskAsync());

只需让任务等待清理 HttpContext 仅针对任务的异步上下文。

迟到的答案,但可能对其他人有用。您可以通过在提交任务时抑制 ExecutionContext 流来做到这一点:

ExecutionContext.SuppressFlow();

var task = Task.Run(async () => {
    await LongRunningMethodAsync();
});

ExecutionContext.RestoreFlow();

或更好:

using (ExecutionContext.SuppressFlow()) {
    var task = Task.Run(async () => {
        await LongRunningMethodAsync();
    });
}

这将防止在提交的任务中捕获 ExecutionContext。因此它将具有 'clean' AsyncLocal 状态。

如上所述,如果它是 CPU 密集的后台工作,我不会在 ASP.net 中执行此操作。