2012-11-13 7 views
9

例外とログのためにタスクが終了したときにキャッチすることは可能ですか?私はCurrentDomain_UnhandledException処理を追加しましたが、これは役に立ちません。例外が発生してログが終了すると、それを捕捉することは可能ですか?

いつものようにTask.Factory.StartNew()を使ってタスクを作成します。そのようなタスクの例外のどこかが発生すると、それは黙ってクラッシュします(しかし、それは永遠に働くはずです、私はLongRunningオプションも使用しています)。だから私はそのような行動について通知されたい。

Ideally anyタスクが例外でクラッシュすると通知されるように、どこかのオプションを設定したいと考えています。

可能であれば、私はに何かを追加する必要があります私は作成するタスクは?もちろん、私はちょうど各タスクの中に大きなtry{} finally{}ブロックを追加することができますが、おそらくもっと良い解決策がありますか?

答えて

2

自分で作成したタスクについては、それはかなり簡単です。Task.Factory.StartNew()を呼び出す独自のメソッドを作成しますが、タスクを返す前にTask.ContinueWith(loggingDelegate, TaskContinuationOptions.OnlyOnFaultedも呼び出してください。

は、では、インフラストラクチャの他のビットによって作成されたタスク(C#5の非同期メソッドを含む)にフォルトハンドラを追加しないという問題があります。

TaskScheduler.UnobservedTaskExceptionを使用することもできますが、他の何かによって既に観察されていない例外に対してのみ呼び出される名前にすることもできます。 (もう一度、あなたにとっては良いかもしれません...)

+0

ありがとうございました!私は 'TaskScheduler.UnobservedTaskException'の方が好きです。私は多くの仕事を作ります。彼らのうちの何人も墜落してはならない。各タスクに「ハンドラ」を追加する代わりに、「グローバル」ハンドラを1つ追加することをお勧めします。 – javapowered

+0

"taskname"や何かを 'UnobservedTaskException'ハンドラに出力できるかどうか知っていますか?例外的に、どの特定のタスクがクラッシュするかは不明であるためです。 – javapowered

+0

@javapowered:そういうことは分かりませんが、私は恐れていますが、例外自体が良いスタートだと思います。 –

0

try/catchブロックにtask.Wait()をラップし、AggregateExceptionをキャッチします。このようなもの -

Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path)); 

// Use this line to throw an exception that is not handled. 
try 
{ 
    task1.Wait(); 
} 
catch (AggregateException ae) 
{ 

    ae.Handle((x) => 
    { 
     if (x is UnauthorizedAccessException) // This we know how to handle. 
     { 
      Console.WriteLine("You do not have permission to access all folders 
           in this path."); 
      Console.WriteLine("See your network administrator or try 
           another path."); 
      return true; 
     } 
     return false; // Let anything else stop the application. 
    }); 
} 

詳細はHandle exceptions thrown by Taskです。

2

例外が発生したときに操作を実行する拡張メソッドを使用できます。 タスクがFaultedになった場合に発生します。そのため、別のタスクを続行する場合は、前のタスクにフォルトが発生していないかどうかを確認し、例外を記録します。

//If you want to chain more tasks.. 
public static Task<T> Continue<T>(this Task<T> task, Action<T> action) 
{ 
    if (!task.IsFaulted) 
    { 
     task.ContinueWith((t) => action(t.Result), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion); 
    } 
    return task; 
} 

public static Task OnException(this Task task, Action<Exception> onFaulted) 
{ 
    task.ContinueWith(c => 
    { 
     var excetion = c.Exception; 
      onFaulted(excetion); 
    }, 
     TaskContinuationOptions.OnlyOnFaulted | 
     TaskContinuationOptions.ExecuteSynchronously); 
    return task; 
} 

あなたが使用することができます:

私は通常、このメソッドを使用

Task.Factory.StartNew(...).OnException(ex => Log(ex)); 

はそれがお役に立てば幸いです。

6

あなたが実行するタスクとしてTestを持っていると仮定すると:

static int Test() 
{ 
    throw new Exception(); 
} 
  1. 最初のアプローチ - 呼び出し側のスレッドでプロセスの例外:

    Task<int> task = new Task<int>(Test); 
    task.Start(); 
    
    try 
    { 
        task.Wait(); 
    } 
    catch (AggregateException ex) 
    { 
        Console.WriteLine(ex); 
    } 
    

    注:例外があることになりますAggregateExceptionと入力します。実際の例外はすべてex.InnerExceptionsプロパティから利用できます。

  2. 第二のアプローチ - いくつかのタスクのスレッドでプロセスの例外:

    static void ExceptionHandler(Task<int> task) 
    { 
        var ex = task.Exception; 
        Console.WriteLine(ex); 
    } 
    

    使用法:

    Task<int> task = new Task<int>(Test); 
    task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted); 
    task.Start(); 
    

参考:How to: Handle Exceptions Thrown by Tasks

ExceptionHandlerこの方法を定義します。

+0

Jonの答えを正しい理由としてマークし、UnobservedTaskExceptionを使用するように提案しました。 – javapowered

0

あなたのタスクで例外を観察し、問題を記録/報告するOnlyOnFaulted継続をタスクに作成することができます。

t.ContinueWith(task => 
{ 
    // Report and log error 
}, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext()); 

上記のコードでは、TaskScheduler.FromCurrentSynchronizationContext()のためにUIスレッドでタスクが実行されます。 winformsを使用しており、ユーザーに通知する必要がある場合は、これが必要な場合があります。

関連する問題