简体   繁体   中英

Why does this sync wrapper over an async method work?

Given:

  • A legacy non-async API method on an ASP.NET/WCF web service
  • New async internal library
  • New async Web API controller that should be used going forward
  • A "storage provider" object that only has an async interface. Its tests pass when run asynchronously, and when run synchronously outside a request context.

The option "go async all the way" is not on the table, since it would break backward compatibility.

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;
    }

Why?

Task.Run steps "outside" the request context - it just runs on the thread pool context. So, it won't deadlock because SaveThingAsync doesn't resume on the request context.

On a side note, the ConfigureAwait(false) is meaningless there, since there is no await to configure.

On another side note, "async all the way" should still be an option. WebAPI and WCF clients don't care whether the implementation they're calling is synchronous or asynchronous. Changing a WCF method implemented synchronously to a WCF method implemented asynchronously is invisible to client code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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