1

HttpClient 非同期メソッド (例: PostAsync、GetAsync など) は、例外がスローされた場合、AggregateException を返します。集約例外に内部例外のリストを含めることができるようになりました。私の質問は、誰かが http クライアントの非同期メソッドの 1 つが複数の内部例外につながる例を提供できますか?

内部例外のリストが存在する可能性がありますが、ほとんどの場合、内部例外は 1 つしか得られないと想定しても安全ですか?

彼らが投げられている理由とそれを処理する方法を知っています。

これをより明確にするために、集計例外をスローする http クライアント非同期メソッドへの単一の呼び出しで、内部例外のリストに複数の例外が含まれることは可能ですか?

4

2 に答える 2

1

await の場合Task.WhenAll()、その WhenAll 内の複数のタスクが例外をスローすると、それらの例外が集約されます。

このような集計例外をスローする TPL は設計によるものであり、別のタスクで例外が発生したという理由だけで、あるタスクの例外が失われることはありません。

例:

var failTask1 = Task.Run(() => { throw new Exception("Example 1"); });
var failTask2 = Task.Run(() => { throw new Exception("Another example"); });
await Task.WhenAll(failTask1, failTask2);
于 2014-12-23T11:33:35.633 に答える
1

内部HttpClient.SendAsync(すべてのリクエストを送信するために使用される内部メソッド) を見ると、Task作成されているのは単純なTaskCompletionSource<HttpResponseMessage>. 呼び出し元のメソッド内でthis.SetTaskFaulted複数回設定されますが、常にif-elseブロック内で設定されます。潜在的に発生する可能性があるSetTaskFaultedのは、例外を設定すると、別の例外が発生する可能性があるということです:

private void SetTaskFaulted(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs, Exception e, TimerThread.Timer timeoutTimer)
{
    this.LogSendError(request, cancellationTokenSource, "SendAsync", e);
    tcs.TrySetException(e);
    HttpClient.DisposeCancellationTokenAndTimer(cancellationTokenSource, timeoutTimer);
}

DisposeCancellationTokenAndTimerを内部的に破棄しCancellationTokenfinallyブロック内でタイマーを破棄します。

private static void DisposeCancellationTokenAndTimer(CancellationTokenSource cancellationTokenSource, TimerThread.Timer timeoutTimer)
{
    try
    {
        cancellationTokenSource.Dispose();
    }
    catch (ObjectDisposedException)
    {
    }
    finally
    {
        HttpClient.DisposeTimer(timeoutTimer);
    }
}

Disposeタイマーは、そのメソッドから例外をスローする可能性があります。それは非常にまれだと確信していますが。

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
    if (request == null)
    {
        throw new ArgumentNullException("request");
    }
    this.CheckDisposed();
    HttpClient.CheckRequestMessage(request);
    this.SetOperationStarted();
    this.PrepareRequestMessage(request);
    CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.pendingRequestsCts.Token);
    TimerThread.Timer timeoutTimer = this.SetTimeout(linkedCts);
    TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
    try
    {
        base.SendAsync(request, linkedCts.Token).ContinueWithStandard(delegate(Task<HttpResponseMessage> task)
        {
            try
            {
                this.DisposeRequestContent(request);
                if (task.IsFaulted)
                {
                    this.SetTaskFaulted(request, linkedCts, tcs, task.Exception.GetBaseException(), timeoutTimer);
                }
                else
                {
                    if (task.IsCanceled)
                    {
                        this.SetTaskCanceled(request, linkedCts, tcs, timeoutTimer);
                    }
                    else
                    {
                        HttpResponseMessage result = task.Result;
                        if (result == null)
                        {
                            this.SetTaskFaulted(request, linkedCts, tcs, new InvalidOperationException(SR.net_http_handler_noresponse), timeoutTimer);
                        }
                        else
                        {
                            if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead)
                            {
                                this.SetTaskCompleted(request, linkedCts, tcs, result, timeoutTimer);
                            }
                            else
                            {
                                this.StartContentBuffering(request, linkedCts, tcs, result, timeoutTimer);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (Logging.On)
                {
                    Logging.Exception(Logging.Http, this, "SendAsync", ex);
                }
                tcs.TrySetException(ex);
            }
        });
    }
    catch
    {
        HttpClient.DisposeTimer(timeoutTimer);
        throw;
    }
    return tcs.Task;
于 2014-12-23T12:04:16.763 に答える