Using "async" (even if it should complete) as part of the MVC route, blocks the route; How can this be avoided?

Consider the following (based on the default MVC template), which is a simplified version of some β€œstuff” that happens in the background - it is perfectly completed and shows the expected result, 20:

public ActionResult Index() { var task = SlowDouble(10); string result; if (task.Wait(2000)) { result = task.Result.ToString(); } else { result = "timeout"; } ViewBag.Message = result; return View(); } internal static Task<long> SlowDouble(long val) { TaskCompletionSource<long> result = new TaskCompletionSource<long>(); ThreadPool.QueueUserWorkItem(delegate { Thread.Sleep(50); result.SetResult(val * 2); }); return result.Task; } 

However, now if we add async to the mix:

 public static async Task<long> IndirectSlowDouble(long val) { long result = await SlowDouble(val); return result; } 

and change the first line of the route to:

 var task = IndirectSlowDouble(10); 

then does not work ; occasionally. If we add breakpoints, return result; in the async method only happens after the route is already completed - basically, it seems that the system does not want to use any thread to resume async until the request is complete. Even worse: if we used .Wait() (or gained access to .Result ), then it would be completely inhibited.

So: what's up with that? The obvious workaround is to "not include async " but this is not easy when using libraries, etc. Ultimately, there is no functional difference between SlowDouble and IndirectSlowDouble (although there is an obvious structural difference).

Note: the exact same thing in the console / winform / etc will work fine.

+16
asynchronous asp.net-mvc task-parallel-library
Nov 29 '12 at 8:29
source share
3 answers

This is due to how the synchronization context is implemented in ASP.NET (Pre.NET 4.5). There are tons of questions about this behavior:

Task.WaitAll hanging with several expected tasks in ASP.NET

Asp.net SynchronizationContext blocks HttpApplication for async extensions?

ASP.NET 4.5 introduces a new implementation of the synchronization context described in this article.

http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx

+10
Nov 29 '12 at 9:15
source share

When you use .Result , there is always the possibility of blocking because .Result blocked by nature. A way to avoid deadlocks is to not block tasks (you should use async and await to the end). The subject is described in detail here:

One fix is ​​to add ConfigureAwait :

 public static async Task<long> IndirectSlowDouble(long val) { long result = await SlowDouble(val).ConfigureAwait(false); return result; } 
+8
Nov 29 '12 at 9:05
source share

Another solution is to use async / await :

 public async Task<ActionResult> Index() { var task = IndirectSlowDouble(10); long result = await task; ViewBag.Message = result.ToString(); return View(); } 
+6
Nov 29 '12 at 9:18
source share



All Articles