在ASP.NET 4.5中使用Partial async / await代码等待异步lambda

时间:2014-05-06 17:01:06

标签: c# asp.net .net-4.0 async-await .net-4.5

我在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代码中完成?

1 个答案:

答案 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,这是没有充分理由的:

http://blogs.msdn.com/b/bclteam/p/asynctargetingpackkb.aspx