I've noticed that when I'm using System.Net.HttpClient
with a short timeout, it may sometimes crash the process, even when it is wrapped in a try-catch block. Here's a short program to reproduce this.
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); } }
Running this will crash the process with the following exception:
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()
Digging in a little, it seems that when HttpClient
aborts the request before a relevant ServicePoint
is created, HttpWebRequest
attempts to create the ServicePoint
, via ServicePointManager.FindServicePoint
, which throws a RequestCanceled. Since this exception is thrown in the thread that attempts to cancel the request, it is not caught, and the process dies.
Am I missing something? Have you run into this issue?
To set an infinite timeout, set the property value to InfiniteTimeSpan. A Domain Name System (DNS) query may take up to 15 seconds to return or time out.
The timeout is defined at the HttpClient level and applies to all requests made with this HttpClient ; it would be more convenient to be able to specify a timeout individually for each request. The exception thrown when the timeout is elapsed doesn't let you determine the cause of the error.
HttpWebRequest.Abort()
is throwing an exception on a background/timer thread. This has nothing to do with HttpClient's Task management.
The exception from HttpWebRequest.Abort()
should be fixed in .NET 4.5 GDR1. http://support.microsoft.com/kb/2750149 http://support.microsoft.com/kb/2750147
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With