1

I am not getting a response from the async DocumentDB ReplaceDocument method when running in a web context (IIS). When running locally, it works just fine. From my research this is appears something to do with a conflicting deadlock with a UI thread?

I am getting good responses from other async calls like so:

this.Client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(this.DatabaseName)).Result;
// and
this.Client.CreateDatabaseAsync(new Database { Id = this.DatabaseName }).Result;
// etc

I'm not using await as in an IIS context is seems to never respond. I'm not sure why, so I removed all the async awaits, and started using .Result and everything works now except the below method.

According to this question Call to await GetFileAsync() never returns and app hangs in WinRT app . I have set up the ConfigureAwait(false) and am calling GetResult(). But the method doesn't return, and the thread eventually closes without return.

var task = this.Client.ReplaceDocumentAsync(this.GetDocumentLink(d.id), d, options);
var configuredTask = task.ConfigureAwait(false);
var awaiter = configuredTask.GetAwaiter();
var result = awaiter.GetResult();

I have also tried the following permutations:

// in a spereate async method
await this.Client.ReplaceDocumentAsync(this.GetDocumentLink(d.id), d, options);
await this.Client.ReplaceDocumentAsync(this.GetDocumentLink(d.id), d, options).ConfigureAwait(false);

// as well as trying a call back
.GetAwaiter().OnCompleted(() => /* never gets here either */);

EDIT

I have this in my Web.config (via :What's the meaning of "UseTaskFriendlySynchronizationContext"?)

<appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>

and

<system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.5" />
</system.web>
Community
  • 1
  • 1
ohmusama
  • 4,159
  • 5
  • 24
  • 44

2 Answers2

4

I believe you're seeing the common deadlock issue that I describe on my blog.

The best solution is not to try to avoid it by using ConfigureAwait(false) everywhere, because it has to be used everywhere. So if you forget one place, or if there's some library code that doesn't use it (which is sadly common), then you can't avoid the deadlock.

The best solution is to embrace the use of await. Replace every call to Task.Wait(), Task<T>.Result, and Task.GetAwaiter().GetResult() with await:

await this.Client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(this.DatabaseName));
await this.Client.CreateDatabaseAsync(new Database { Id = this.DatabaseName });

var result = await this.Client.ReplaceDocumentAsync(this.GetDocumentLink(d.id), d, options);

I'm not using await as in an IIS context is seems to never respond.

Please ensure you are targeting .NET 4.5 and have set targetFramework to 4.5 in your web.config.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I added my web config stuff, also, I'll give the async from top to bottom a try, I'm running from a WebAPI, anything I should worry about before I dive into this 300 line change? – ohmusama Jun 20 '16 at 19:11
  • @ohmusama: If you have synchronous APIs available, it may be faster to change to sync-all-the-way. – Stephen Cleary Jun 20 '16 at 19:14
  • I think the issue is `ReplaceDocumentAsync` in the documentDb library may not use ConfigureAwait(false) and thus, I cannot Wait on it. Probably a typo. I'm going to decomplie it and check. – ohmusama Jun 20 '16 at 19:55
  • They call into a helper class with `await TaskHelper.InlineIfPossible(another task)` which inside may or may not await, which is probably why I'm getting inconsistent results – ohmusama Jun 20 '16 at 19:59
  • I had some reflection along the way, with an Invoke(), solved it with `ContinueWith` And it works, Thanks! – ohmusama Jun 20 '16 at 20:28
  • @ohmusama: `await` should also replace all instances of `ContinueWith`. – Stephen Cleary Jun 20 '16 at 20:43
  • @ohmusama: It's better (read: more maintainable and reliable) to use `await` *instead of* `ContinueWith`. Details are [on my blog](http://blog.stephencleary.com/2015/01/a-tour-of-task-part-7-continuations.html). – Stephen Cleary Jun 20 '16 at 23:17
  • Very good answer. In my case I was using WPF. This answer complements this: http://stackoverflow.com/a/28601723/194717 – Tony Aug 13 '16 at 20:20
0

In my case there were similar task cancel/error, internal exception shown "DictionaryError" or Aggregation Exception. At least I figure out that main reason caused issue was just using endpoint to CosmosDb emulator with http://. After changing it https://localhost:8081 - everything started work.

InPickSys
  • 1
  • 1