zoukankan      html  css  js  c++  java
  • 调试System.AggregateException-即使在异步代码中也是如此

    顾名思义,AggregateException用于在单个异常中对一个或多个异常进行批处理。在本文中,我将向您展示为什么会发生此异常,以及如何在C代码中调试它。

    错误的产生和处理

    让我们从强制一个产生新的AggregateException开始。这个异常在.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)
    {
    }

    在上面的例子中,我们执行两个任务,每个任务都抛出一个异常。通过调用WaitAll,我们告诉.NET调用并等待这两个任务的结果。这两个任务的组合结果将是AggregateException。

    调试这个错误

    从调试器中的上一个示例检查异常时,我们在InnerExceptions属性中看到两个抛出的异常:

    正如名称中承诺的那样,AggregateException是其他异常的包装器。在该示例中,ArgumentException和UnauthorizedAccessException都可用作内部异常。在某些情况下,您将为每个异常添加一个catch blog,如下所示:
    try
    {
        ...
    }
    catch (ArgumentException ex1)
    {
        // Log and re-throw
    }
    catch (UnauthorizedAccessException ex2)
    {
        // Log and swallow
    }

    这样,您就可以向用户生成个别的错误消息,记录异常,但只能重新抛出其中一条或第三条。AggregateException提供了一个方便的名为Handle的小助手方法,而不是在InnerExceptions属性中的每个异常上循环:

    try
    {
        ...
    }
    catch (AggregateException ae)
    {
        ae.Handle(inner =>
        {
            // Log inner
            ...
            return inner is UnauthorizedAccessException;
        });
    }

    在本例中,Handle方法记录每个异常。func需要返回一个bool,指示是否处理了每个异常。在本例中,我们告诉Handle方法处理了UnauthorizedAccessException,但没有处理ArgumentException。这将导致AggregateException被抛出回调用代码,但InnerExceptions属性中没有UnauthorizedAccessException(因为我们将该异常标记为已处理)。

    来自HttpClient的AggregateExceptions

    在处理System.Net.Http.HttpClient类时,可能会遇到AggregateException。这主要是在使用旧API实现异步代码时(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方法作为示例,但是如果使用其他异步消息(如PostAsync),代码看起来会很相似。如前所述,taskapi的异常被包装在AggregateException中,在InnerExceptions属性中包含HTTP异常。

    要获得实际的异常,您有一系列选项。我将重复使用记录异常的必要性来说明。让我们从我在上一个示例中向您展示的Handle方法开始:

    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方法中移了出来。

    最后,如果您在.NET4.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并引发底层异常。在大多数情况下,这就是你想要的。移植现有异步代码以使用await关键字的另一个好处。

  • 相关阅读:
    C++解决单纯形表
    VS2010 MFC Excel(3)
    VS2010 MFC Excel(1)
    VS2010 MFC 读取Excel(2)
    读取数量不定的输入数据
    牛顿插值
    连接数据库
    雅克比迭代
    NOIP模拟 24
    NOIP模拟 23
  • 原文地址:https://www.cnblogs.com/yilang/p/12563904.html
Copyright © 2011-2022 走看看