34

System.Net.HttpClient短いタイムアウトで使用していると、try-catchブロックでラップされている場合でも、プロセスがクラッシュすることがあることに気付きました。これを再現するための短いプログラムがあります。

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);
    }
}

これを実行すると、次の例外を除いてプロセスがクラッシュします。

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()

少し掘り下げてみると、関連するものが作成さHttpClientれる前にリクエストを中止すると、を介してリクエストを作成しようとし、RequestCanceledがスローされるようです。この例外は、リクエストをキャンセルしようとするスレッドでスローされるため、キャッチされず、プロセスは終了します。ServicePointHttpWebRequestServicePointServicePointManager.FindServicePoint

私は何かが足りないのですか?この問題に遭遇しましたか?

4

2 に答える 2

21

HttpWebRequest.Abort()バックグラウンド/タイマー スレッドで例外をスローしています。これは HttpClient のタスク管理とは関係ありません。

の例外はHttpWebRequest.Abort()、.NET 4.5 GDR1 で修正する必要があります。 http://support.microsoft.com/kb/2750149 http://support.microsoft.com/kb/2750147

于 2013-03-18T17:45:05.357 に答える
4

HttpClient の非同期ハンドラーがタスクを管理する方法に何らかのバグがあるようです。アイテムを並行して起動できましたが、同期して実行すると機能します。未処理のエラーを防ぐだけかどうかはわかりません。これは並列タスクを実行しましたが、オフにしてから実際には非同期ではありません。私のコンピューターでは、常に 5 ラウンドに達し、クラッシュすることがありました。1秒後にタイムアウトするように設定しても、スレッドが非同期の場合、スレッドのクラッシュがまだ爆発するようです。

これはバグだと思います。これが意図した動作だとは思えません。

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();
        }
    }
}
于 2013-03-18T17:15:32.370 に答える