I have the nuget package Esri.ArcGISRuntime and I need to call the method QueryTask.ExecuteAsync in one of my Web API 2 controllers. There is no synchronous counter part so in my library c# code I am using a wrapper like
private QueryResult ExecuteSync()
{
var queryResults = ExecuteAsync();
queryResults.Wait();
return queryResults.Result;
}
private async Task<QueryResult> ExecuteQueryTaskAsync()
{
var queryTask = new QueryTask(_uri);
return await queryTask.ExecuteAsync(_query).ConfigureAwait(false);
}
Which works perfectly in my program/service. But using ExecuteSync
this way in a Web API 2 controller causes it to completely freeze up and never return a response.
I have done some research and believe the culprit is mentioned here: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
I absolutely do not want to use the function asynchronously. The above functions are so core and hidden deep within like 4 wrappers, that it would be a major overhaul of my library class to bubble up async methods just to support this one web api call.
I am looking for work-arounds/hacks/suggestions around this weird behavior of web API to allow me to run this async method synchronously and not have it deadlock
As a general rule, every piece of code that is not in a view model and/or that does not need to go back on the main thread should use ConfigureAwait false. This is simple, easy and can improve the performance of an application by freeing the UI thread for a little longer.
ConfigureAwait(continueOnCapturedContext: false) is used to avoid forcing the callback to be invoked on the original context or scheduler. This has a few benefits: Improving performance.
If the await task. ConfigureAwait(false) involves a task that's already completed by the time it's awaited (which is actually incredibly common), then the ConfigureAwait(false) will be meaningless, as the thread continues to execute code in the method after this and still in the same context that was there previously.
In the code that relies on the asynchronous programming model ( async / await keywords), ConfigureAwait() calls are often used to manage the synchronization context. The way ConfigureAwait() calls work and their usage scenarios are explained in detail in this Microsoft .
I absolutely do not want to use the function asynchronously.
I have to say it, though. Asynchronous code is the best solution. The operation you're doing is asynchronous, and exposing a synchronous API for it is problematic at best.
Does it take time? Sure. But your code will be better off for it.
I am looking for work-arounds/hacks/suggestions
I have an entire article on the subject of brownfield async development, where I cover all the known hacks along with their drawbacks.
In your particular case (calling from WebApi on non-Core ASP.NET and considering that it does work from a Console/Win32Service-style app), I'd say the Thread Pool Hack should work for you. It looks like this:
private QueryResult ExecuteSync()
{
return Task.Run(() => ExecuteAsync()).GetAwaiter().GetResult();
}
The idea is that ExecuteAsync
is run on a thread pool thread, outside of the request context. The request thread is then blocked until the asynchronous work completes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With