簡體   English   中英

使用語句中的HttpClient導致任務被取消

[英]HttpClient in using statement causes Task cancelled

我為我的api調用創建了一個FileResult : IHttpActionResult webapi返回類型。 FileResult從另一個URL下載文件,然后將流返回給客戶端。

最初我的代碼有一個如下所示的using語句:

public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
    try
    {
        HttpResponseMessage response;
        using (var httpClient = new HttpClient())
        {

            response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new System.Net.Http.StreamContent(
                                    await httpClient.GetStreamAsync(this.filePath))
            };
        }
        return response;
    }
    catch (WebException exception)
    {...}
}

但是,這會間歇性地導致TaskCanceledException 我知道如果在異步調用完成之前處理了HttpClient,Task的狀態將變為取消。 但是因為我使用了awaitContent = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath)) ,它應該阻止HttpClient在任務完成過程中被處理掉。

為什么該任務被取消? 這不是因為超時,因為這發生在最小的請求上,並不總是發生在大請求上。

當我刪除using語句時,代碼正常工作:

public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
    try
    {
        HttpResponseMessage response;
        var httpClient = new HttpClient();

        response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new System.Net.Http.StreamContent(
                                await httpClient.GetStreamAsync(this.filePath))
        };
        return response;
    }
    catch (WebException exception)
    {...}
}

知道為什么使用導致了這個問題嗎?

我知道如果在異步調用完成之前處理了HttpClient,Task的狀態將變為取消。 但是因為我使用了await:Content = new System.Net.Http.StreamContent(等待httpClient.GetStreamAsync(this.filePath)),它應該阻止HttpClient在任務完成過程中被處理掉。

但是這項任務做了什么? 它得到了流。 因此,您的代碼最終會得到一個Stream ,當它關閉HttpClient時可能會或可能不會被完全讀取。

HttpClient專門用於重用(和同時使用),因此我建議完全刪除using並將HttpClient聲明移動到static類成員。 但是,如果要關閉並重新打開客戶端,則應該能夠通過在關閉HttpClient之前將流完全入內存來使其工作。

我遇到了類似於Task Canceled異常的問題。 如果您嘗試捕獲AggregateException或在WebException下面捕獲所有Exception塊,您可能會發現它捕獲它,但有一個例外,條目說明“任務已被取消”

我做了一些調查,發現AggregateException很容易產生誤導,如各種線程所述;

將HttpClient設置為太短的超時會導致進程崩潰

如何判斷HttpClient何時超時?

httpclientgetasync中的錯誤應該拋出webexception而不是taskcanceledexception

我最終更改了我的代碼以設置顯式超時(從app.config文件中讀取asyncTimeoutInMins );

        string jsonResponse = string.Empty;
        try
        {
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.BaseAddress = new Uri(Properties.Settings.Default.MyWebService);
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                httpClient.Timeout = new TimeSpan(0, asyncTimeoutInMins, 0);

                HttpResponseMessage response;

                response = await httpClient.GetAsync("/myservice/resource");

                // Check the response StatusCode
                if (response.IsSuccessStatusCode)
                {
                    // Read the content of the response into a string
                    jsonResponse = await response.Content.ReadAsStringAsync();
                }
                else if (response.StatusCode == HttpStatusCode.Forbidden)
                {
                    jsonResponse = await response.Content.ReadAsStringAsync();

                    Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));

                    Environment.Exit((int)ExitCodes.Unauthorised);
                }
                else
                {
                    jsonResponse = await response.Content.ReadAsStringAsync();

                    Logger.Instance.Warning(new HttpRequestException(string.Format("The response StatusCode was {0} - {1}", response.StatusCode.ToString(), jsonResponse)));

                    Environment.Exit((int)ExitCodes.ApplicationError);
                }
           }

        }
        catch (HttpRequestException reqEx)
        {
            Logger.Instance.Error(reqEx);

            Console.WriteLine("HttpRequestException : {0}", reqEx.InnerException.Message);

            Environment.Exit((int)ExitCodes.ApplicationError);
        }
        catch (Exception ex)
        {
            Logger.Instance.Error(ex);

            throw;
        }

        return jsonResponse;

暫無
暫無

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

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