Given:
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.