簡體   English   中英

異步方法缺少等待

[英]The async method lacks await

我在這個主題上發現了很多東西,但是似乎沒有一個示例/答案可以解決我們的問題。 我們不斷收到警告,指出以下方法(以及其他類似方法)缺少等待,但是當我們嘗試添加等待時,我們會收到“無法等待此消息”(無論我們嘗試在哪里添加等待)。 我們做錯了什么?

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

非常感謝您的協助!

您已將方法標記為async但未使用await 您的方法沒有理由是async 您可以將定義重寫為

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

async本質上說:“在這種方法中,我們將await asnyc調用”

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

然后我們擺脫了不必要的try / catch:

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方法,以接受客戶端應將標頭添加為參數的客戶端。

原因是您沒有像等待的那樣等待任何東西。異步調用結束時會出現結果。 嘗試這個

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

您不能同時使用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));

您是否嘗試過:

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

基於此:

var webApiResponse = Task.Run(() => _webApiClient.GetAsync(requestUri)).Result;

我建議您退后一步,嘗試了解async await為您准備做什么。 有一些學習曲線,但是可以確保您不會因為使用它而使事情變得更糟。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM