如果在ASP.NET MVC中执行以下代码,您可以在调试窗口中看到它将在await
之后正确恢复线程的文化,即使ManagedThreadId发生更改:
public async Task<ActionResult> Index()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
await SomeMethod();
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
return View();
}
private async Task SomeMethod()
{
await Task.Delay(100).ConfigureAwait(false);
}
然后我将ConfigureAwait(false)从SomeMethod()移到Index(),除此之外,它与上面的代码相同:
public async Task<ActionResult> Index()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
await SomeMethod().ConfigureAwait(false);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
return View();
}
private async Task SomeMethod()
{
await Task.Delay(100);
}
现在它不会恢复我的文化,但始终将其设置为new CultureInfo("en-US")
。但我希望使用这两种方法,结果必须相同。目前还不清楚,为什么会发生这种情况。
答案 0 :(得分:6)
如果您使用await task.ConfigureAwait(false)
,那么该方法的其余部分(以及您从那里调用的任何内容)将不会在原始上下文中执行。但这不会影响逻辑调用树中更高的代码。
我认为这是唯一符合逻辑的方法。如果必须在原始上下文中执行更高的代码(这是非常常见的),那么ConfigureAwait()
库内代码深处的某个地方确实不应该影响它。
为了使其更加具体,如果await
根据您的行为表现出来,以下在Winforms中使用ConfigureAwait()
的简单示例将无效:
async void ButtonClicked(object sender, EventArgs e)
{
textBlock.Text = "Downloading";
await DownloadAsync();
textBlock.Text = "Finished";
}
async Task DownloadAsync()
{
data = await new HttpClient().GetStringAsync(url).ConfigureAwait(false);
}
答案 1 :(得分:1)
您可以创建自己的awaiter,使文化流程具有await
延续回调,即使它发生在不同的池线程上也是如此。所以,你的电话会是这样的:
await SomeMethod().WithCulture();
Stephen Toub在PFX Team blog上详细说明了如何执行此操作,查找CultureAwaiter
。
答案 2 :(得分:0)
(来自手机)
你不仅失去了线程文化。你正在失去整个背景。
当存在SynchronizationContext时,将继续发布到该SynchronizationContext。在ASP.NET中,它是一个请求处理程序线程,在客户端UI中是UI线程。
ConfigureAwait(false)指示生成的状态机不发布到捕获的(如果有)SynchronizationContext。
索引永远不应该使用它,但是应该从那里调用任何代码。