9

是否可以捕获任何任务因异常和日志而终止的时间?我已经添加了CurrentDomain_UnhandledException处理,但这没有帮助。

Task.Factory.StartNew()我照常使用创建任务。当此类任务异常中的某个地方发生时,它会静默崩溃(但它应该永远工作,我也在使用LongRunning选项)。因此,我希望收到有关此类行为的通知。

理想情况下,我想在某处设置一些选项,以便在任何任务因异常而崩溃时得到通知。

如果不可能,那么我可能应该在我创建的每个任务中添加一些东西?当然我可以try{} finally{}在每个任务中添加大块,但可能有更好的解决方案?

4

5 回答 5

6

假设您有一个Testas 任务要运行:

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. 第二种方法 -在某些任务的线程中处理异常

    定义ExceptionHandler这种方式:

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

参考:如何:处理任务引发的异常

于 2012-11-13T09:32:29.187 回答
2

对于您自己创建的任务,它相当简单:创建您自己的方法来调用Task.Factory.StartNew(),然后Task.ContinueWith(loggingDelegate, TaskContinuationOptions.OnlyOnFaulted在返回任务之前调用。

问题在于,这不会为其他基础设施创建的任务添加故障处理程序 - 包括 C# 5 中的异步方法。不过,它仍然可能对您有用。

您也可以使用TaskScheduler.UnobservedTaskException, 但根据名称,该名称仅用于其他尚未观察到的异常。(再一次,这对你来说可能很好......)

于 2012-11-13T09:30:43.713 回答
2

您可以使用在发生异常时执行操作的扩展方法。当任务出现故障时会发生这种情况。因此,如果它还有其他任务要继续,下一个可以检查上一个任务是否出错并记录异常。

我通常使用这种方法:

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

希望能帮助到你。

于 2012-11-13T09:31:38.370 回答
0

将您的包装task.Wait()在 try/catch 块中并 catch 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.
    }); 
}

可以在此处找到详细信息 -处理 Task 引发的异常

于 2012-11-13T09:31:29.953 回答
0

您可以在您的任务上创建一个 OnlyOnFaulted 延续,它观察异常并记录/报告问题。

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

上面的代码将在 UI 线程上运行任务,因为TaskScheduler.FromCurrentSynchronizationContext(). 如果您使用的是 winforms 并且需要通知用户,这可能是必要的。

于 2012-11-13T09:32:38.020 回答