デバッグシステム.Asyncコードでさえ


私は再び一般的なデバッグを支援するためにここにいる.NET例外.今回はかなり一般的なシステムをデバッグしたいです.AggregateException.名前が示すように、AggregateExceptionは1つ以上の例外を一括して1つの例外で使用します.この投稿では、なぜこの例外が発生したのか、C Chorseコードでデバッグする方法を示します.

エラーの原因と処理


新しいことを強制し始めましょうAggregateException . 例外は大量に使用されます.ASP . NETのタスクライブラリでは、タスクを含む例を選択する理由はありません.
Task task1 = Task.Factory.StartNew(() => { throw new ArgumentException(); } );
Task task2 = Task.Factory.StartNew(() => { throw new UnauthorizedAccessException(); } );

try
{
    Task.WaitAll(task1, task2);
}
catch (AggregateException ae)
{
}
上の例では、2つのタスクをスピンします.呼び出しによってWaitAll 私たちは言います.を呼び出すと、2つのタスクのそれぞれから結果を待ちます.つのタスクの組み合わせ結果はAggregateException .
次のエラーメッセージのいずれかのため、おそらくこの記事に来たでしょう.
  • システムAggregateException 1つ以上のエラーが発生しました.
  • 仕事は取り消された
  • 'システムmscorlibで発生しました.DLL
  • 次の節では、それぞれのデバッグと修正方法を示します.

    エラーのデバッグ


    デバッガで前の例から例外を検査するときは、InnerExceptions プロパティー

    名前で約束通り.AggregateException は他の例外のラッパーです.この例ではArgumentExceptionUnauthorizedAccessException 内部の例外として利用できます.
    いくつかのシナリオでは、以下のような例外についてcatchブログを追加します.
    try
    {
        ...
    }
    catch (ArgumentException ex1)
    {
        // Log and re-throw
    }
    catch (UnauthorizedAccessException ex2)
    {
        // Log and swallow
    }
    
    この方法では、ユーザーに個々のエラーメッセージを生成することができますが、例外をログオンしますが、それらのいずれか、または何かを再度スローします.では、InnerExceptions プロパティAggregateException 便利な小さなヘルパーメソッドHandle :
    try
    {
        ...
    }
    catch (AggregateException ae)
    {
        ae.Handle(inner =>
        {
            // Log inner
            ...
            return inner is UnauthorizedAccessException;
        });
    }
    
    この例ではHandle メソッドごとに例外を記録します.The func Aを返す必要bool 各例外が処理されたかどうかを示すこの場合、我々はHandle メソッドUnauthorizedAccessException は処理されるが、ArgumentException . これはAggregateException 呼び出し元のコードにスローされるが、UnauthorizedAccessExceptionInnerExceptions プロパティ(既に処理された例外をマークしたので).

    HttpClientからのAggregate例外


    を扱うときSystem.Net.Http.HttpClient クラス、あなたはAggregateException . これはほとんどの場合、古いAPIを使用してasyncコードを実装する場合ですWait , ContinueWith , など)例を見てみましょう.
    try
    {
        var client = new HttpClient();
        var task = client.GetStringAsync("https://httpstat.us/500");
        task.Wait();
        var result = task.Result;
    }
    catch (AggregateException ex)
    {
        throw ex;
    }
    
    へのリクエストhttps://httpstat.us/500 のHTTPステータスコードを返す500 をスローするHttpRequestException . 私は、使用しているGetStringAsync 例としての方法ですが、他のasyncメッセージを使用する場合、コードは似ていますPostAsync . 以前に見たように、タスクAPIの例外はAggregateException , HTTP例外を含むInnerExceptions プロパティ.
    実際の例外を取得するには、オプションの範囲があります.私は、説明するために例外を記録する必要を再利用します.前の例で示したハンドルメソッドから始めましょう.
    try
    {
        ...
    }
    catch (AggregateException ex)
    {
        ex.Handle(inner =>
        {
            if (inner is HttpRequestException)
            {
                // Log the exception
    
                return true;
            }
    
            return false;
        });
    }
    
    内部の例外がタイプかどうかチェックしていますHttpRequestException そしてその場合、Handle この例外が処理されたメソッド.他のどんなシナリオでもHandle 元の例外を返すfalse ).
    もう一つのアプローチはContinueWith メソッドのキャッチと処理AggregateException :
    var client = new HttpClient();
    var task = client
        .GetStringAsync("https://httpstat.us/500")
        .ContinueWith(t =>
        {
            try
            {
                return t.Result;
            }
            catch (AggregateException ex)
            {
                ex.Handle(inner =>
                {
                    if (inner is HttpRequestException)
                    {
                        // Log the exception
    
                        return true;
                    }
    
                    return false;
                });
            }
            catch (Exception ex)
            {
                throw ex;
            }
    
            return null;
        });
    task.Wait();
    var result = task.Result;
    
    私は基本的にちょうど中から前にtry catchを動かしましたContinueWith メソッド.
    最後に、あなたがいるならば.NET 4.5(あなたはおそらく、そうでない場合、あなたはすべきである)あなたはawait キーワード
    var client = new HttpClient();
    try
    {
        var result = await client.GetStringAsync("https://httpstat.us/500");
    }
    catch (HttpRequestException ex)
    {
        // Log the exception
    }
    catch (Exception ex)
    {
        throw ex;
    }
    
    
    コードがどのようにキャッチするかに注目してくださいHttpRequestException の代わりにAggregateException . これが原因です.NETは自動的にAggregateException を返します.これはほとんどの場合に必要なものです.既存のasyncコードを移植するもう一つの利点await キーワード.
    また、このシリーズの他の記事を読むことを確認してください.Debugging common .NET exceptions .

    あなたのユーザーは、より少しの誤りを評価しますか?


    エルマ.IOは簡単なエラーログとアップタイム監視サービスです.ネットすべてのサポートを使用してエラーのコントロールを取り戻す.NET Webおよびログフレームワーク.
    ➡️ Error Monitoring for .NET Web Applications ⬅️
    この記事はエルマに初めて現れた.ioのブログhttps://blog.elmah.io/debugging-system-aggregateexception-even-in-async-code/