3

In my asp.net application I was calling some async method of one my nuget package I added into my application. Now I have a sync method in which I need to call async method of .dll I added. So for that I called those method and to retrieve result I used

var value = myDllClient.MyMethod().GetAwaiter().GetResult(); and
var value = myDllClient.MyMethod().Result;,

But none of these worked for me but the thread went into never ending process. I never received anything So I used

var value = Task.Run(async ()=> await myDllClient.MyMethod()).Result;

is surprisingly working fine. I don't know how is it working? Can anyone help me to understand this mystery?

Thanks in advance

Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
Mukeem Ahmed
  • 93
  • 1
  • 2
  • 11

2 Answers2

6

So for that I called those method and to retrieve result I used

A better solution is to use await and allow the asynchrony to grow naturally through the code base. If you do have to do sync-over-async, then direct blocking like that may cause deadlocks.

await captures a context by default, and in your case the await inside of MyMethod is capturing an ASP.NET request context, which existed on pre-Core versions of ASP.NET. Then, the calling code blocks a thread in that request context by calling GetResult()/Result. Later, when the await is ready to continue, it schedules the remainder of MyMethod to that context. But it will never be run because there's a thread blocked in that context waiting for MyMethod to complete.

The reason Task.Run doesn't deadlock is because MyMethod uses the thread pool context instead of an ASP.NET request context. This is the "thread pool hack" approach to doing sync-over-async. However, Task.Run is not recommended on ASP.NET; if possible, change the code to use await instead.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Changing code all the way async is not possible as I working on a very old service of microsoft build on asp.net. Now I was required to implement one of their new dll. If Task.Run is not preferred then what Should I use as I can't convert it all await? Thanks your above wonderful guidance @Stephen Cleary.. – Mukeem Ahmed Jan 25 '20 at 15:45
  • 1
    @MukeemAhmed: In that case, I would use something like [this `NoContext` method](https://github.com/StephenCleary/AsyncEx/blob/e637035c775f99b50c458d4a90e330563ecfd07b/src/Nito.AsyncEx.Tasks/SynchronizationContextSwitcher.cs#L36-L54) – Stephen Cleary Jan 26 '20 at 01:10
2

By wrapping your call in Task.Run you are isolating that code from ASP.NET's SynchronizationContext and thus your code doesn't deadlock.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59