Using Asynchronous Method Calls in ActionFilter

Topics: ASP.NET MVC
Dec 28, 2013 at 11:23 PM
I have run into a problem on MVC 5 where I can't get an asynchronous call from an action filter to work. I realise action filters are not asynchronous, however in my action filter I am calling a service that ultimately may call a remote web service using HTTPClient, which only supports asynchronous operation. Whenever an asynchronous call is made, I get what appears to be a deadlock, web site hangs, no response to the HTTP request. As my service layer implements caching, if I somehow populate the cache initially and the service call returns from cache synchronously, then the ActionFilter executes with no issue (as expected).

I understand from various discussions on Stack Overflow this relates to blocking of the calling thread and the callback unable to invoke on the blocked calling thread. I have attempted to use techniques suggested which involve using ConfigureAwait(false) with C# 5.0 async/await calls, or using Task.Factory.StartNew(), but in all cases I can see that the asynchronous call is being made on the same thread ID, hence dead lock issue persists.

Any ideas on a workaround other than creating a new thread directly?
Dec 28, 2013 at 11:48 PM
Edited Dec 29, 2013 at 1:44 AM
I just solved this a few minutes after posting.

The solution is to use Task.Factory.StartNew(), but you must ensure you specify TaskCreationOptions.LongRunning in the method call. This guarantees a different thread will be used from your ActionFilter thread for the asynchronous method, avoiding the deadlock issue.
public override void OnActionExecuting()
{
...
// This will not work - it will call on the same thread, causing deadlock
// var serviceResult = myService.GetResultAsync(someParameter).Result;

// This will always make the service call on a new thread
var serviceResult = Task.Factory.StartNew(() => myService.GetResultAsync(someParameter).Result, TaskCreationOptions.LongRunning).Result;
...
}
Marked as answer by mixja on 12/28/2013 at 4:48 PM
Jan 9, 2014 at 3:33 PM
I found this article on Stack Overflow on handling the general case of running async methods synchronously:
How would I run an async Task<T> method synchronously?
Jan 9, 2014 at 7:20 PM
Great thanks!

Sent from my iPhone