以干净的AsyncLocal状态启动任务

Fla*_*ien 6 .net-core asp.net-core asp.net-core-1.1

在ASP.NET Core中,我IHttpContextAccessor用来访问current HttpContextHttpContextAccessor使用AsyncLocal<T>

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

我尝试了Task.RunThread.Start但是每次情况下,上下文似乎都会继承并IHttpContextAccessor返回旧的上下文,无论我尝试执行什么(有时甚至是来自其他请求的上下文)。

如何启动AsyncLocal状态为干净的任务,然后IHttpContextAccessor返回null

小智 8

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

ExecutionContext.SuppressFlow();

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

ExecutionContext.RestoreFlow();
Run Code Online (Sandbox Code Playgroud)

或更好:

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

这将防止在提交的任务中捕获 ExecutionContext。因此,它将具有“干净”的 AsyncLocal 状态。

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


Ily*_*kov 2

您可以等待长时间运行的任务并在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;
}
Run Code Online (Sandbox Code Playgroud)

你可以运行一个单独的线程,这并不重要。

Task.Run(async () => await LongRunningTaskAsync());
Run Code Online (Sandbox Code Playgroud)

只需让任务等待清理HttpContext任务的异步上下文即可。