簡體   English   中英

HttpClient.PostAsJsonAsync永遠不會看到帖子成功和響應的時間

[英]HttpClient.PostAsJsonAsync never sees when the post is succeeding and responding

我們正在使用HttpClient將json發布到一個寧靜的Web服務。 在一個例子中,我們遇到了困擾我們的事情。 使用postman,fiddler等工具,我們可以發布到端點並看到它正在工作。 當我們對HttpClient.PostAsJsonAsync做同樣的事情時,我們可以在我們發布的軟件中驗證它收到的數據就好了。 但是,我們的PostAsJsonAsync最終會超時,而不是給我們一個響應。

我們與創建我們正在消費的服務的團隊合作,加上我們的額外測試,我們還沒有真正超時的服務。

每次我們使用HttpClient發布帖子時,我們都可以驗證我們發布的目標軟件是否確實獲得了數據。 每當我們從任何其他工具發布到目標軟件的帖子時,我們總是很快看到狀態代碼為200的響應。關於HttpClient的某些內容未能接受來自此特定服務的響應。 有沒有人知道我們可以從這里看到什么?

這是代碼(雖然它是如此千篇一律,我幾乎覺得不需要)

public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
    {
        using (var client = new HttpClient())
        {
            if (timeoutMinutes > 0)
            {
                client.Timeout = new TimeSpan(0,timeoutMinutes,0);
            }
            var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
            var response = client.PostAsJsonAsync(useUrl, o).Result;
            if(response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                return response.Content.ReadAsStringAsync().Result;
            }
            return "";
        }

    }

這個:

var response = client.PostAsJsonAsync(useUrl, o).Result;

導致代碼死鎖。 在阻止異步API的情況下通常會出現這種情況,這就是為什么你會遇到“我看不到任何響應”的原因

這怎么會造成僵局? 您在包含同步上下文的環境中執行此請求的事實,可能是屬於UI的同步上下文。 它正在執行異步請求,當響應到達時,它會繼續通過IO完成線程,該線程嘗試將延續發布到同一UI上下文中,該上下文當前被.Result調用阻止。

如果要同步發出HTTP請求,請改用WebClient 如果要正確利用異步API,則await而不是使用.Result進行阻止。

我有同樣的問題, 這個SO答案為我解決了。

簡而言之,您必須使用ConfigureAwait(false)擴展來避免死鎖:

var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);

您有沒有理由不遵循異步等待模式? 你正在調用異步方法,但不是在等待它。 您沒有說調用您的REST服務的代碼是Windows窗體還是ASP.NET應用程序,但是.Result 可能會導致您遇到問題

你可以像這樣重構你的方法:

public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
    using (var client = new HttpClient())
    {
        if (timeoutMinutes > 0)
        {
            client.Timeout = new TimeSpan(0,timeoutMinutes,0);
        }
        var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
        var response = await client.PostAsJsonAsync(useUrl, o);
        if(response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            return await response.Content.ReadAsStringAsync();
        }
        return "";
    }

}

這是對@Justin Helgerson解決方案的略微修改。 您的方法中有2個阻止.Result調用; 一旦你去異步,你應該修復它們。

public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
    using (var client = new HttpClient())
    {
        if (timeoutMinutes > 0)
        {
            client.Timeout = new TimeSpan(0,timeoutMinutes,0);
        }
        var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
        var response = await client.PostAsJsonAsync(useUrl, o);
        if(response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            return await response.Content.ReadAsStringAsync();
        }
        return "";
    }
}

注意我還根據TAP模式將方法重命名為PostDataAsync

System.Net.ServicePointManager.Expect100Continue = false;

我們案例中的一行代碼解決了這個問題。 來自不同團隊的開發人員提供了該建議,並且可行。 我還沒有去谷歌,並閱讀它足以提供解釋的內容。

暫無
暫無

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

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