7

Tôi đã tạo loại trả lại webView FileResult : IHttpActionResult cho các cuộc gọi api của mình. FileResult tải xuống một tệp từ một url khác và sau đó trả về luồng cho máy khách.HttpClient trong sử dụng tuyên bố nguyên nhân Công việc bị hủy

Ban đầu mã của tôi đã có một tuyên bố using như dưới đây:

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) 
    {...} 
} 

Tuy nhiên điều này không liên tục sẽ gây ra một TaskCanceledException. Tôi biết rằng nếu HttpClient được xử lý trước khi cuộc gọi không đồng bộ kết thúc, trạng thái của Task sẽ thay đổi thành hủy bỏ. Tuy nhiên vì tôi sử dụng một số đang chờ trong: Content = new System.Net.Http.StreamContent(await httpClient.GetStreamAsync(this.filePath)) nên ngăn không cho HttpClient bị loại bỏ ở giữa nhiệm vụ hoàn thành.

Tại sao tác vụ đó bị hủy? Nó không phải là do một thời gian chờ vì điều này đã xảy ra trên các yêu cầu nhỏ nhất và không phải luôn luôn xảy ra trên các yêu cầu lớn.

Khi tôi xóa bảng sao kê using mã làm việc đúng cách:

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) 
    {...} 
} 

Bất cứ ý tưởng tại sao sử dụng gây ra vấn đề này?

+0

Bạn đã thử sử dụng trình gỡ lỗi chưa? Kiểm tra từng bước một. – kevintjuh93

+0

Vâng tôi có. Nó không thực sự hữu ích vì ngoại lệ không được ném ở đây nhưng ở một vị trí hoàn toàn khác. Nó xảy ra trong đường ống Owin mà tôi đang sử dụng khi xác thực và nó đang chờ yêu cầu tiếp theo. – Rafi

+0

'TaskCanceledException' có bất kỳ ngoại lệ bên trong nào không? –

Trả lời

9

Tôi biết rằng nếu HttpClient được xử lý trước khi cuộc gọi không đồng bộ kết thúc tình trạng của công tác sẽ chuyển sang hủy. Tuy nhiên kể từ khi tôi sử dụng một await trong: Content = new System.Net.Http.StreamContent (chờ đợi httpClient.GetStreamAsync (this.filePath)) mà nên ngăn chặn HttpClient từ được xử lý tắt ở giữa hoàn thành nhiệm vụ.

Nhưng nhiệm vụ đó làm gì? Nó có luồng. Vì vậy, mã của bạn kết thúc bằng một số Stream có thể hoặc có thể không được đọc hoàn toàn khi nó đóng HttpClient.

HttpClient được thiết kế đặc biệt để tái sử dụng (và sử dụng đồng thời), vì vậy tôi khuyên bạn nên gỡ bỏ các using hoàn toàn và di chuyển tờ khai HttpClient cho một thành viên static lớp. Nhưng nếu bạn muốn đóng và mở lại khách hàng, bạn có thể làm cho nó hoạt động bằng cách đọc luồng hoàn toàn vào bộ nhớ trước khi đóng HttpClient.

4

Tôi gặp sự cố tương tự với các trường hợp ngoại lệ Công việc bị hủy. Nếu bạn cố gắng bắt AggregateException hoặc có một nắm bắt tất cả Exception khối bên dưới WebException của bạn, bạn cũng có thể thấy rằng bạn bắt nó, với một ngoại lệ với sự gia nhập nêu rõ "Một nhiệm vụ đã bị hủy bỏ"

tôi đã làm một số điều tra và phát hiện ra rằng AggregateException là khá gây hiểu nhầm như được mô tả trong các chủ đề khác nhau;

Setting HttpClient to a too short timeout crashes process

How can I tell when HttpClient has timed out?

Bug in httpclientgetasync should throw webexception not taskcanceledexception

tôi đã kết thúc việc thay đổi mã của tôi để thiết lập một thời gian chờ rõ ràng (nơi asyncTimeoutInMins được đọc từ file app.config);

 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; 
+0

Như đã đề cập trong chú thích ở trên, ngoại lệ không bị bắt ở đó nhưng trong lớp logic xác thực. – Rafi

Các vấn đề liên quan