C#异步方法 - 需要帮助

Mat*_*ull 0 c# asp.net-mvc asynchronous async-await asp.net-web-api

我有一个消耗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
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定我在这里遗失了什么?一些帮助将不胜感激.

编辑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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

控制器:

public async Task<ActionResult>  GetAll()
{
    return PartialView("_GetAllDocumentsPartial", await _docRepo.GetAll());
}
Run Code Online (Sandbox Code Playgroud)

对于以下答案中描述的更改,如上所述进行调试时仍会出现同样的问题.但是我得到"任务被取消了".存储库中方法中的catch的异常.

堆栈跟踪.

Bad*_*dri 5

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

假设您像这样调用Web API.

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

    return View();
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是当异步调用完成时,它需要在跳出的原始线程上继续,但是你通过调用来阻塞该线程Result().调用Result块并等待异步调用返回,async continuation等待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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

更好的是将动作方法更改为public async Task<ActionResult> Index()等待GetAll().

如果您觉得这个答案有帮助,那么您一定要感谢Stephen Cleary.