Хотя это намного сложнее, вы можете изобразить await
как ContinueWith
.Так, если вы напишите, например:
DoSomeStuff();
await WaitAsync()
DoMoreStuff();
Он будет переписан следующим образом:
DoSomeStuff();
WaitAsync().ContinueWith(_ => DoMoreStuff());
.ConfigureAwait
устанавливает контекст, в котором будет выполняться продолжение.При ConfigureAwait(true)
(по умолчанию) продолжение будет выполняться в том же контексте, что и вызывающая сторона.При ConfigureAwait(false)
продолжение будет выполняться в инвариантном контексте по умолчанию в пуле потоков.С нашим предыдущим упрощением давайте представим, что ConfigureAwait(true)
будет переписано в ContinueWithSameContext
и ConfigureAwait(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 не равен нулю.