为什么这个同步包装器通过异步方法工作?

时间:2016-04-06 18:13:44

标签: c# asynchronous task

假设:

  • ASP.NET / WCF Web服务上的传统非异步API方法
  • 新的异步内部库
  • 应该继续使用的新异步Web API控制器
  • 仅具有异步接口的“存储提供程序”对象。它的测试在异步运行时传递,并在请求上下文之外同步运行时传递。

表中没有“一直异步”选项,因为它会破坏向后兼容性。

public class Impl {
    // This works fine when used asynchronously
    public Task<Guid> SaveThingAsync(Thing thingToSave) {
        return await _storageProvider.saveAsync(thingToSave);
    }

    public Guid SaveThing(Thing thingToSave) {
        // "Obviously", this code creates a deadlock when called 
        // from within the request context
        // return SaveThingAsync(thingToSave).Result

        // Not so obviously, this also creates a deadlock
        // return SaveThingAsync(thingToSave)
        //            .ConfigureAwait(false)
        //            .GetAwaiter()
        //            .GetResult()

        // This was deadlocking, but magically stopped
        // return Task.Run(
        //        async () => await SaveThingAsync(thingToSave)
        //                      .ConfigureAwait(false)
        //               ).Result;

        // This one works
        var saveTask = Task.Run(async () => 
                            await SaveThingAsync(thingToSave)));
        var result = saveTask.ConfigureAwait(false).GetAwaiter().GetResult();
        return result;
    }

为什么?

1 个答案:

答案 0 :(得分:1)

Task.Run步骤&#34;外部&#34;请求上下文 - 它只在线程池上下文中运行。因此,它不会死锁,因为SaveThingAsync不会在请求上下文中恢复。

在旁注中,ConfigureAwait(false)在那里毫无意义,因为没有await可供配置。

另一方面,&#34;一直异步&#34;应该还是一个选择。 WebAPI和WCF客户端不关心他们调用的实现是同步还是异步。将与异步实现的WCF方法同步实现的WCF方法更改为客户端代码不可见。