异步方法缺少等待

时间:2016-01-15 16:52:50

标签: c# asynchronous asp.net-web-api

我在这个主题上找到了很多,但没有一个例子/答案似乎解决了我们的问题。我们不断收到警告,说下面的方法(以及其他类似的方法)都没有等待,但是当我们尝试添加等待时,我们得到了#34;无法等待这个" (无论我们在哪里尝试添加等待)。我们做错了什么?

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
        {
            try
            {
                _webApiClient = new HttpClient { BaseAddress = _baseAddress };
                if (appendHeader) AppendDefaultHeaders();
                var webApiResponse = Task.Run(() => _webApiClient.GetAsync(requestUri)).Result;
                var responseContent = webApiResponse.Content.ReadAsStringAsync().Result;
                return JsonConvert.DeserializeObject<T>(responseContent);
            } 
            catch (Exception ex) {
                throw ex;
            }
        }

非常感谢任何帮助!

6 个答案:

答案 0 :(得分:4)

您已标记方法async,但未使用await。您的方法没有理由async。您可以将定义重写为

protected T PerformGet<T>(string requestUri, bool appendHeader)

async基本上说'在这种方法中,我们将await asnyc call'

答案 1 :(得分:4)

async是一个关键字,它将方法标记为编译器完全重写以支持async / await模式的候选方法。

在内部使用await关键字的每个位置都会分割该方法。如果您将某个方法标记为async但不使用await,则会因为您将其标记为不必要,或者您忘记使用await而抱怨。这就是你得到编译器错误的原因。

现在,下一步是将await添加到您的方法中,但这意味着稍微更改它:

  • 为了运行任务而启动另一项任务是一步太多
  • 在任务上使用.Result容易出现死锁,这就是await派上用场的地方

所以让我们改写你的方法。首先,我们摆脱对Task.Result的调用,并替换为await

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

然后我们摆脱了不必要的任务任务:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await _webApiClient.GetAsync(requestUri);
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

然后我们摆脱了不必要的尝试/捕获:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    _webApiClient = new HttpClient { BaseAddress = _baseAddress };
    if (appendHeader) AppendDefaultHeaders();
    var webApiResponse = await _webApiClient.GetAsync(requestUri);
    var responseContent = await webApiResponse.Content.ReadAsStringAsync();
    return JsonConvert.DeserializeObject<T>(responseContent);
}

然后我们将HttpClient对象放入using语句中:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    using (var client = new HttpClient { BaseAddress = _baseAddress })
    {
        if (appendHeader) AppendDefaultHeaders(client);
        var response = await client.GetAsync(requestUri);
        var responseContent = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    }
}

这会删除字段,这在执行异步工作时通常是一个坏主意,并使其成为此方法的本地概念。这还需要更改AppendDefaultHeaders方法以接受客户端应将标头添加为参数。

答案 2 :(得分:2)

原因是你没有等待任何事情。在异步调用结束时结果。试试这个

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)    
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

答案 3 :(得分:1)

您无法同时使用await.Result。这是一个或另一个。 Result将阻止你的线程,直到异步方法完成,就像它是一个同步方法。 await表示在方法运行时线程将被移回线程池,并且当方法完成时,它将获取另一个线程以继续该函数的其余部分。所以你的功能应该是:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
    {
        try
        {
            _webApiClient = new HttpClient { BaseAddress = _baseAddress };
            if (appendHeader) AppendDefaultHeaders();
            var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
            var responseContent = await webApiResponse.Content.ReadAsStringAsync().;
            return JsonConvert.DeserializeObject<T>(responseContent);
        } 
        catch (Exception ex) {
            throw ex;
        }
    }

此外,Task.Run(...)有点无意义,只需使用var webApiResponse = await _webApiClient.GetAsync(requestUri));

即可

答案 4 :(得分:0)

你试过这个:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

答案 5 :(得分:0)

基于此:

wxSplitterWindow

我建议您退后一步,尝试了解var webApiResponse = Task.Run(() => _webApiClient.GetAsync(requestUri)).Result; async正在尝试为您做些什么。有一点学习曲线,但它会确保你不会因为使用它而使事情变得更糟。