2013-03-12 32 views
32

Tôi nhận thấy rằng khi tôi đang sử dụng System.Net.HttpClient với thời gian chờ ngắn, đôi khi có thể làm hỏng quy trình, ngay cả khi nó được bao bọc trong khối thử. Đây là một chương trình ngắn để tái tạo điều này.Đặt HttpClient thành quá trình treo thời gian chờ quá ngắn

public static void Main(string[] args) 
{ 
    var tasks = new List<Task>(); 
    for (int i = 0; i < 1000; i++) 
    { 
     tasks.Add(MakeHttpClientRequest()); 
    } 
    Task.WaitAll(tasks.ToArray()); 

} 

private async static Task MakeHttpClientRequest() 
{    
    var httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(1) }; 
    var request = "whatever"; 
    try 
    { 
     HttpResponseMessage result = 
      await httpClient.PostAsync("http://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api_key=766c0ac7802d55314fa980727f747710", 
           new StringContent(request));    
     await result.Content.ReadAsStringAsync();     
    } 
    catch (Exception x) 
    { 
     Console.WriteLine("Error occurred but it is swallowed: " + x); 
    } 
} 

Chạy này sẽ sụp đổ quá trình với các ngoại lệ sau đây:

Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.Net.WebException: The request was canceled 
    at System.Net.ServicePointManager.FindServicePoint(Uri address, IWebProxy proxy, ProxyChain& chain, HttpAbortDelegate& abortDelegate, Int32& abortState) 
    at System.Net.HttpWebRequest.FindServicePoint(Boolean forceFind) 
    at System.Net.HttpWebRequest.get_ServicePoint() 
    at System.Net.AuthenticationState.PrepareState(HttpWebRequest httpWebRequest) 
    at System.Net.AuthenticationState.ClearSession(HttpWebRequest httpWebRequest) 
    at System.Net.HttpWebRequest.ClearAuthenticatedConnectionResources() 
    at System.Net.HttpWebRequest.Abort(Exception exception, Int32 abortState) 
    at System.Net.HttpWebRequest.Abort() 
    at System.Net.Http.HttpClientHandler.OnCancel(Object state) 
    at System.Threading.CancellationCallbackInfo.ExecutionContextCallback(Object obj) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.CancellationCallbackInfo.ExecuteCallback() 
    at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args) 
    at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) 
    --- End of inner exception stack trace --- 
    at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) 
    at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException) 
    at System.Threading.CancellationTokenSource.TimerCallbackLogic(Object obj) 
    at System.Threading.TimerQueueTimer.CallCallbackInContext(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.TimerQueueTimer.CallCallback() 
    at System.Threading.TimerQueueTimer.Fire() 
    at System.Threading.TimerQueue.FireNextTimers() 
    at System.Threading.TimerQueue.AppDomainTimerCallback() 

Đào trong một chút, có vẻ như rằng khi HttpClient hủy bỏ yêu cầu trước khi có liên quan ServicePoint được tạo ra, HttpWebRequest nỗ lực để tạo ra các ServicePoint, thông qua ServicePointManager.FindServicePoint, trong đó ném một RequestCanceled. Vì ngoại lệ này được ném vào chuỗi cố gắng hủy bỏ yêu cầu, nó không bị bắt và quá trình này sẽ chết.

Tôi có thiếu gì đó không? Bạn đã gặp phải vấn đề này chưa?

+0

Đây là một lỗi tuyệt vời. a) Bạn có thể thử thêm một lượt thử quanh toàn bộ Main không? b) Bạn có thể móc sự kiện EventScheduler.UnobservedTaskException Event không? – usr

+0

@usr: đã thử cả hai và như mong đợi nó không giúp ích gì. Try-catch trên main chỉ nắm bắt được công cụ chủ đề chính và ngoại lệ xử lý sự cố không phải là một UnobservedTaskException. –

+0

Bạn không thể nắm bắt được tổng hợp ngoại lệ? Và đối phó với nó từ đó? bắt (AggregateException ae) { } – PaulG

Trả lời

20

HttpWebRequest.Abort() đang ném ngoại lệ trên chuỗi nền/hẹn giờ. Điều này không liên quan gì đến việc quản lý tác vụ của HttpClient.

Ngoại lệ từ HttpWebRequest.Abort() phải được khắc phục trong .NET 4.5 GDR1. http://support.microsoft.com/kb/2750149 http://support.microsoft.com/kb/2750147

+2

Chắc chắn là một vấn đề về bản vá. Tôi có thể xác nhận rằng điều này hoạt động tốt trên máy tính xách tay vá lỗi cập nhật Windows 8 của tôi, nhưng không hoạt động trên máy tính xách tay công việc của tôi nhận bản vá từ bản cập nhật của công ty. –

+1

Bất kỳ tùy chọn nào nếu bạn không thể cài đặt bản cập nhật? (quay trở lại HttpWebRequest cũ có lẽ?) –

4

Có vẻ như đó là một số loại lỗi trong cách trình xử lý async cho HttpClient đang quản lý các tác vụ. Tôi đã có thể khởi động các mục song song, nhưng chạy chúng một cách đồng bộ và nó hoạt động. Tôi không chắc chắn nếu bạn muốn chỉ cần ngăn chặn các lỗi unhandled hay không. Điều này chạy song song nhiệm vụ, nhưng họ không phải là async thực sự kể từ khi tôi tắt nó đi. Trên máy tính của tôi, tôi sẽ luôn luôn nhận được đến 5 viên đạn và nó sẽ sụp đổ. Ngay cả khi tôi thiết lập nó để timeout sau một giây, nó giống như các tai nạn trong các chủ đề vẫn sẽ thổi lên nếu họ không đồng bộ.

Tôi nghĩ rằng đó là một lỗi, tôi không thể tưởng tượng đây là hành vi dự định.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Net.Http; 

namespace TestCrash 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       Parallel.ForEach(Enumerable.Range(1, 1000).ToList(), i => 
       { 
        Console.WriteLine(i); 
        using (var c = new HttpClient { Timeout = TimeSpan.FromMilliseconds(1) }) 
        { 
         var t = c.GetAsync("http://microsoft.com"); 
         t.RunSynchronously(); //<--comment this line and it crashes 
         Console.WriteLine(t.Result); 
        } 
       }); 
      } 
      catch (Exception x) 
      { 
       Console.WriteLine(x.Message); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 
+1

Dường như có một lỗi trong HttpWebRequest (HttpClient sử dụng trong nó Gửi). Xem câu trả lời của Tratcher. –

+0

Không nên thực sự sử dụng Parallel.ForEach với async. Đây là quái vật. – Matt

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