简体   繁体   English

在ASP.NET 4.5中使用部分异步/等待代码等待异步lambda

[英]Wait on async lambda with Partial async/await code in ASP.NET 4.5

I have an HTTPHandler in asp.net that I would like to convert to be async using 4.5 async await code. 我在asp.net中有一个HTTPHandler,我想使用4.5 async await代码将其转换为async。 However not all of our code is 4.5 so the inner parts of our app (libraries, infrastructure) needs to stay on 4.0 at the moment. 但是,并不是我们的所有代码都是4.5,因此应用程序的内部部分(库,基础架构)目前需要保持4.0。 I'm running into an issue where I want to provide a lambda to some of our shared libraries. 我遇到了一个问题,我想为我们的某些共享库提供lambda。 The lambda is async but I need the library code to wait on it to complete, but without deadlocking. Lambda是异步的,但是我需要库代码等待它完成,但是没有死锁。 So far I haven't been able to figure it out. 到目前为止,我还无法弄清楚。

Let's say the handler looks like this: 假设处理程序如下所示:

// .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);
    }
}

And then SharedLibrary looks something like this: 然后,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
    }
}

As the code stands now, the call to PostProcess returns before the lambda fully finishes running. 如代码所示,在lambda完全完成运行之前,将返回对PostProcess的调用。 If I switch PostProcess to Func <int,int,Task > instead and call as PostProcess(1,2).Wait() then I deadlock. 如果我改为将PostProcess切换为Func <int,int,Task >并以PostProcess(1,2).Wait()的方式调用,则会死锁。 Is there a way to accomplish in mixed 4.5/4.0 code like this? 有没有办法在这样的混合4.5 / 4.0代码中完成?

Use ConfigureAwait(false) inside your lambda: 在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
  }
}

This way you should avoid deadlocking on the UI thread. 这样,您应该避免UI线程上的死锁。

Edit 编辑

As mentioned on the comments, once ConfigureAwait(false) is used inside ASP.NET, The HttpContext is no longer avaliable inside the continuation (code after await ) 如评论所述,一旦在ASP.NET中使用ConfigureAwait(false)则HttpContext在延续中不再可用( await之后的代码)

I would suggest you look into the Microsoft.Bcl.Async library deployed for .NET 4 via Nuget, so you could use async/await properly without initializing Threads for no good reason: 我建议您查看通过Nuget为.NET 4部署的Microsoft.Bcl.Async库,这样就可以在没有正当理由的情况下正确使用async/await而无需初始化线程:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM