Set HttpContext.Current 在 await 的延续中不一样

Set HttpContext.Current is not the same in continuation of await

根据 Stephen Cleary 的 this 回答,我了解到 HttpContextSynchronizationContext 流动。因此,给定以下代码:

    public async Task<ActionResult> Index()
    {
        var outerContext = System.Web.HttpContext.Current = new HttpContext(
            new HttpRequest(null, "http://test.com", null),
            new HttpResponse(new StreamWriter("C:/Path")));

        Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));

        await Task.Run(
            delegate
            {
                Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));
            });
        
        Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));
        
        return View();
    }

我希望控制台输出为:

True
False
True

然而,实际输出是:

True
False
False

调试后,continuation 中的上下文似乎设置为请求的原始上下文,即之前我通过调用 HttpContext.Current = ... 手动设置的上下文。这是什么原因?它是否在执行 await 之后的代码之前的某处设置为请求上下文?

HttpContext.Current 未被 保存并由 await 恢复。 await 将捕获 SynchronizationContext.Current 并使用它来恢复执行。

请求开始时,会创建一个新的请求上下文(其中包括一个特定的 HttpContext.Current 实例)。每当 AspNetSynchronizationContext 恢复对该请求上下文的执行时,它将 HttpContext.Current 设置为该请求上下文的实例。

因此,在 await 之后,HttpContext.Current 将与 Index 开头的实例相同,而不是您的代码分配给它的任何实例。