我有一个使用Web API操作的异步方法。它似乎陷入了一个循环。我的理由是因为如果我在catch块的第1行放置一个断点,并且进入,它实际上从未击中第二行。
我最初返回一个包含100,000+(~30mb)行的数据集,并认为由于请求的大小可能会很慢,但在更改我的Web API操作以仅返回1行后问题仍然存在。当我浏览到Web API解决方案的URI时,肯定会返回数据,我在浏览器中返回了JSON。
public async Task<IEnumerable<Document>> GetAll()
{
try
{
var response = await _client.GetAsync(
string.Format("{0}/api/document", _baseURI));
// never hits line below
return await response.Content.ReadAsAsync<Document>()
as IEnumerable<Document>;
}
catch (Exception ex)
{
// handle exception
}
}
我不确定我在这里遗失了什么?一些帮助将不胜感激。
编辑1
在回答一些问题时,我有一个由MVC项目引用的Web API项目。我不得不对JSON反序列化的原始问题进行一些更改。
存储库:
public async Task<IEnumerable<Document>> GetAll()
{
try
{
string json;
var response = await _client.GetAsync(string.Format(
"{0}/api/document", _baseURI)).ConfigureAwait(false);
var resource = await response.Content.ReadAsAsync<Document>();
using(var reader = new StreamReader(resource.ToString()))
{
json = reader.ReadToEndAsync().ToString();
}
return JsonConvert.DeserializeObjectAsync<Document>(json)
as IEnumerable<Document>;
}
catch (Exception)
{
throw;
}
}
控制器:
public async Task<ActionResult> GetAll()
{
return PartialView("_GetAllDocumentsPartial", await _docRepo.GetAll());
}
根据以下答案中描述的更改,如上所述进行调试时仍会出现同样的问题。但是我得到“任务被取消了”。存储库中方法中的catch的异常。
答案 0 :(得分:5)
您是否从ASP.NET应用程序调用{{1}}?既然你已经将MVC标记为这个问题,我就是这么认为的。如果你这样做,那么你就是在陷入困境。
假设您像这样调用Web API。
GetAll().Result
这里的问题是当异步调用完成时,它需要在跳出的原始线程上继续,但是你通过调用public ActionResult Index()
{
var result = GetAll().Result;
return View();
}
来阻止该线程。调用Result块并等待异步调用返回,async continuation等待ASP.NET线程继续可用。那是一个死锁。
像这样更改你的GetAll()。
Result()
这表明当异步调用完成时不需要保留上下文,因此继续发生在线程池线程(而不是ASP.NET)中。
最好将操作方法更改为public async Task<IEnumerable<Document>> GetAll()
{
try
{
var response = await _client.GetAsync(
string.Format("{0}/api/document", _baseURI))
.ConfigureAwait(false);
// never hits line below
return await response.Content.ReadAsAsync<Document>()
as IEnumerable<Document>;
}
catch (Exception ex)
{
// handle exception
}
}
并等待public async Task<ActionResult> Index()
。
如果您觉得此答案有帮助,您只能感谢Stephen Cleary。
答案 1 :(得分:1)
你在外部图书馆工作吗?如果是这样,请尝试添加ConfigureAwait(false);
var response = await _client.GetAsync(string.Format("{0}/api/document", _baseURI))
.ConfigureAwait(false);
它与告知等待不捕获当前上下文有关。调用ConfigureAwait将确保使用ThreadPool执行该方法的其余部分。关于这个主题的一些好的阅读可以在Stephen Cleary的博客上找到here。
答案 2 :(得分:0)
如果它适用于网络浏览器但不使用代码,那么您可能需要发送一个接受标头。添加以下行
_client.DefaultRequestHeaders.Accept = new MediaTypeWithQualityHeaderValue("application/json");