问题描述
我有一个从控制器调用的库异步函数.我期望HttpContext.Current在所有地方都使用ConfigureAwait(false)等待后为null,但在控制器中不为null.有人可以解释为什么吗?
I have a library async function called from controller. I expected HttpContext.Current to be null after await with ConfigureAwait(false) everywhere, but in controller it is not null. Can somebody explain why?
//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
.因此,如果您编写例如:
Though it is much more complex than that, you can picture await
as a kind of ContinueWith
. So if you write for instance:
DoSomeStuff();
await WaitAsync()
DoMoreStuff();
它被重写为:
DoSomeStuff();
WaitAsync().ContinueWith(_ => DoMoreStuff());
.ConfigureAwait
设置继续执行的上下文.使用 ConfigureAwait(true)
(默认设置),延续将在与调用者相同的上下文中执行.使用 ConfigureAwait(false)
,延续将在线程池的默认不变上下文中执行.通过前面的简化,让我们想象将 ConfigureAwait(true)
重写为 ContinueWithSameContext
,将 ConfigureAwait(false)
重写为 ContinueWithThreadPool
>.
.ConfigureAwait
sets the context in which the continuation will execute. With ConfigureAwait(true)
(the default), the continuation will execute in the same context as the caller. With ConfigureAwait(false)
, the continuation will execute in the default invariant context, on the threadpool.With our previous simplification, let's imagine ConfigureAwait(true)
will be rewritten to ContinueWithSameContext
and ConfigureAwait(false)
to ContinueWithThreadPool
.
现在,如果我们有嵌套方法,会发生什么?例如,您的代码:
Now what happens if we have nested methods? For instance, your code:
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不为空.
Rewritten this way, you see that the continuation of WaitAsync
will run on the same context as Task<ActionResult> Index()
, explaining why the HttpContext isn't null.
这篇关于为什么HttpContext.Current在带有ConfigureAwait的异步/等待中不为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!