0

我有一个使用 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 异常。

堆栈跟踪。

4

3 回答 3

5

您是GetAll().Result从 ASP.NET 应用程序调用吗?既然您已将 MVC 标记为这个问题,我假设是这样。如果你这样做了,那么你就陷入了僵局。

假设您像这样调用 Web API。

public ActionResult Index()
{
    var result = GetAll().Result;

    return View();
}

这里的问题是当异步调用完成时,它需要在它跳出的原始线程上继续,但是你通过调用Result(). 调用结果阻塞并等待异步调用返回,异步继续等待 ASP.NET 线程可用以继续。那是死锁。

像这样更改您的 GetAll() 。

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
    }
}

这表明当异步调用完成时不需要保留上下文,因此继续发生在线程池线程(不是 ASP.NET)中。

最好将 action 方法更改为public async Task<ActionResult> Index()和 await GetAll()

如果您发现此答案有帮助,则只能感谢Stephen Cleary

于 2013-07-12T16:48:26.460 回答
1

你在外部图书馆工作吗?如果是这样,请尝试添加 ConfigureAwait(false);

var response = await _client.GetAsync(string.Format("{0}/api/document", _baseURI))
                            .ConfigureAwait(false);

它与告诉 await 不要捕获当前上下文有关。调用 ConfigureAwait 将确保使用 ThreadPool 执行该方法的其余部分。可以在 Stephen Cleary 的博客上找到有关该主题的一些好读物

于 2013-07-12T16:48:49.103 回答
0

如果它适用于网络浏览器但不使用代码,那么您可能需要发送一个接受标头。添加以下行

_client.DefaultRequestHeaders.Accept = new MediaTypeWithQualityHeaderValue("application/json");
于 2013-07-12T17:18:54.950 回答