为什么 HttpContext.Current 在 async/await 中使用 ConfigureAwait 时不为



我有一个从控制器调用的库异步函数。我希望 HttpContext.Current 在任何地方都使用 ConfigureAwait(false) 等待后为空,但在控制器中它不为空。有人可以解释为什么吗?

//in libraby
public class MyClass
{
public async Task WaitAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
var httpContext = System.Web.HttpContext.Current; // null, OK
}
}
public class HomeController : Controller
{
public async Task<ActionResult> Index()
{
var class1 = new MyClass();
await class1.WaitAsync();
var httpContext = System.Web.HttpContext.Current; // not null, WHY???
return View("Index");
}
}

虽然它比这复杂得多,但你可以await想象成一种ContinueWith。因此,如果您例如编写:

DoSomeStuff();
await WaitAsync()
DoMoreStuff();

它被重写为:

DoSomeStuff();
WaitAsync().ContinueWith(_ => DoMoreStuff());

.ConfigureAwait设置执行延续的上下文。使用ConfigureAwait(true)(默认值),延续将在与调用方相同的上下文中执行。使用ConfigureAwait(false),延续将在线程池的默认固定上下文中执行。 通过我们之前的简化,让我们想象ConfigureAwait(true)将被重写为ContinueWithSameContextConfigureAwait(false)ContinueWithThreadPool.

现在,如果我们有嵌套方法会发生什么?例如,您的代码:

public async Task WaitAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
var httpContext = System.Web.HttpContext.Current; // null, OK
}
public async Task<ActionResult> Index()
{
var class1 = new MyClass();
await class1.WaitAsync();
var httpContext = System.Web.HttpContext.Current; // not null, WHY???
return View("Index");
}

这也被重写了:

public Task WaitAsync()
{
return Task.Delay(TimeSpan.FromSeconds(1))
.ContinueWithThreadPool(_ => 
{
var httpContext = System.Web.HttpContext.Current; // null, OK
});
}        
public Task<ActionResult> Index()
{
var class1 = new MyClass();
return class1.WaitAsync().ContinueWithSameContext(_ =>
{
var httpContext = System.Web.HttpContext.Current; // not null, WHY???
return View("Index");
}
}

以这种方式重写,你会看到WaitAsync的延续将在与Task<ActionResult> Index()相同的上下文上运行,这解释了为什么HttpContext不为空。

相关内容

  • 没有找到相关文章

最新更新