我有nuget包Esri.ArcGISRuntime,我需要在我的一个Web API 2控制器中调用方法QueryTask.ExecuteAsync。没有同步计数器部分所以在我的库c#代码中我使用的是
这样的包装器 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);
}
在我的程序/服务中完美运行。但是在Web API 2控制器中以这种方式使用ExecuteSync
会导致它完全冻结并且永远不会返回响应。
我做了一些研究,并相信罪魁祸首在这里提到: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
我绝对不想异步使用该功能。上面的函数是如此核心并且隐藏在4个包装器的深处,这将是我的库类的一个重大改进,冒泡异步方法只是为了支持这个web api调用。
我正在寻找围绕Web API的这种奇怪行为的解决方法/黑客/建议,以允许我同步运行此异步方法而不会使其死锁
答案 0 :(得分:14)
但是,我必须说出来。异步代码是最好的解决方案。您正在进行的操作是异步的,并且为其公开同步API充其量是有问题的。我绝对不想异步使用该功能。
需要时间吗?当然。但是你的代码会更好。
我正在寻找解决方法/黑客/建议
我有an entire article on the subject of brownfield async development,其中涵盖了所有已知的黑客及其缺点。
在您的特定情况下(从非核心ASP.NET上调用WebApi 和考虑到它确实可以在Console / Win32Service风格的应用程序中运行),我会说Thread Pool Hack应该为你工作。它看起来像这样:
private QueryResult ExecuteSync()
{
return Task.Run(() => ExecuteAsync()).GetAwaiter().GetResult();
}
这个想法是ExecuteAsync
在请求上下文之外的线程池线程上运行。然后阻止请求线程,直到异步工作完成。
答案 1 :(得分:0)
您正在调用的对象.Wait()on也是一项任务,您尚未对其进行配置。将.ConfigureAwait(false)添加到ExecuteQueryAsync的返回值。
或者,更好的是,WebAPI也可以是同步,因此整个堆栈异步会更好。