我在asp.net中有一个HTTPHandler,我希望使用4.5 async等待代码将其转换为异步。然而,并非所有代码都是4.5,因此我们的应用程序(库,基础架构)的内部部分目前需要保持在4.0。我遇到了一个问题,我想为一些共享库提供lambda。 lambda是异步的,但我需要库代码来等待它完成,但没有死锁。到目前为止,我还没弄清楚。
假设处理程序如下所示:
// .NET 4.5 website
public class MyHandler : HttpTaskAsyncHandler
{
public override async Task ProcessRequestAsync(HttpContext context)
{
var someLibrary = new SharedLibrary();
someLibrary.PostProcess = async (x,y) => {
await ProcessXY(x,y);
}
await someLibrary.ProcessAsync();
// write out some content here
}
private async Task ProcessXY(int x, int y) {
// make some external calls
var someLib = new SomeOtherLibrary();
await someLib.CallAsync(x,y);
}
}
然后SharedLibrary看起来像这样:
// .NET 4.0 class library
public class SharedLibrary {
public Action<int,int> PostProcess { get; set; }
public Task ProcessAsync() {
return Task.Factory.StartNew(() => Process(), CancellationToken.None,TaskCreationOptions.None,TaskScheduler.FromCurrentSynchronizationContext());
}
public void Process() {
// do some processing
if (PostProcess != null) {
// call PostProcess synchronously
PostProcess(1,2);
}
// do some final processing
}
}
现在代码就停止了,在lambda完全运行之前,对PostProcess的调用会返回。如果我将PostProcess切换为Func <int,int,Task
&gt;相反,并调用PostProcess(1,2).Wait()然后我死锁。有没有办法在这样的混合4.5 / 4.0代码中完成?
答案 0 :(得分:0)
在lambda中使用ConfigureAwait(false)
:
public override async Task ProcessRequestAsync(HttpContext context)
{
var someLibrary = new SharedLibrary();
someLibrary.PostProcess = async (x,y) => {
await ProcessXY(x,y).ConfigureAwait(false);
}
await someLibrary.ProcessAsync();
// write out some content here
}
public class SharedLibrary {
public Func<int,int,Task> PostProcess { get; set; }
public void Process() {
// do some processing
if (PostProcess != null) {
// call PostProcess synchronously
PostProcess(1,2).Wait();
}
// do some final processing
}
}
这样你就可以避免在UI线程上死锁。
修改强>
正如评论中所提到的,在ASP.NET内部使用ConfigureAwait(false)
后,HttpContext在延续中不再可用
(await
之后的代码)
我建议您通过Nuget查看为.NET 4部署的Microsoft.Bcl.Async
库,这样您可以正确使用async/await
而无需初始化Threads,这是没有充分理由的: