【问题标题】:Handling Aggregate Exceptions in Service Fabric处理 Service Fabric 中的聚合异常
【发布时间】:2017-10-18 11:27:48
【问题描述】:

假设我有一个 Web API 服务,它调用我的用户服务来返回用户个人资料信息等。

UserProfileService 可以抛出 UserNotFoundException。抛出时,它会被序列化并作为AggregateException 中的内部异常发送,可以在调用方法中捕获。此服务使用 Service Fabric 的远程服务进行 RPC。

我的 WebAPI 像这样调用我的服务:

[HttpGet]
public async Task<IActionResult> Get(int id)
{
    try
    {
        var profile = await _userService.GetProfileAsync(int id);
        return Json(profile);
    } catch (AggregateException ae)
    {
        // Here I want to call NotFound() if `UserNotFoundException`
        //   was thrown, otherwise...
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

这里有几个问题:

  1. 如何处理预期的异常?

天真地我会做这样的事情:

try { /* ... */ } catch (AggregateException ae)
{
    foreach(var e in ae.InnerExceptions)
    {
        if (e is UserNotFoundException)
        {
            return NotFound();
        }
    }

    return errorResponse ?? StatusCode(StatusCodes.Status500InternalServerError);
}

但问题是,如果有多个例外,只有一个会“获胜”。而且,我相信 - 尽管不能保证,最早添加的 Exceptions 将具有优先权,因为它们在 InnerExceptions 中的索引较低。我是不是在想这个,这个解决方案会好吗?我的自定义异常只有在我知道应该被抛出时才会被抛出,对吗?

这引出了我的另一个问题:

  1. 在什么情况下,您会在 AggregateException 中检索多个异常。

当你有Task a调用Task b调用Task cc抛出,b不抛出,a抛出时,你会得到包含a和的聚合异常c 的例外情况?

【问题讨论】:

    标签: c# exception-handling asp.net-core azure-service-fabric


    【解决方案1】:

    我建议在所有相关类中抛出异常,并且只在 Web 服务中捕获那些向 Web 服务调用者报告一条错误消息的异常。使异常处理尽可能简单。

    换种说法:如果任何代码出现问题,只需throw new Exception() 用一个字符串指示发生的事情和地点。你唯一能做try/catch的地方就是[httpget] Get()

    如果你真的知道你在做什么,你可以实现序列化异常的东西,但是你不会在这里问这个:-)

    【讨论】:

    • 我不确定我是否关注,抱歉 :(
    • 据我了解,当您使用 Service Fabric 的 Remoting 库执行 RPC 时,远程服务中引发的异常会被序列化,通过线路发送,并由 Service Fabric 运行时反序列化为 AggregateException/图书馆——如果这样更清楚的话!
    【解决方案2】:

    我会反着回答你的问题:

    2) AggregateException 有一个contructor,它允许IEnumerable&lt;Exception&gt; 作为参数。这就是它可以包含多个内部异常的方式。这意味着您的聚合异常不会包含多个内部异常,除非您显式抛出带有多个内部异常的AggregateException。假设您有一个Task a 调用Task b 调用Task c。如果c 抛出了一个异常,而ab 中没有捕获到该异常,那么a 将抛出一个带有内部AggregateExceptionAggregateException 以及一个由c 抛出的内部异常。

    1) 你的例子工作得很好。如果你想让它更短一点,你可以通过内部异常捕获它:

    try
    {
        // ...
    }
    catch (AggregateException ex) when (ex.InnerException is UserNotFoundException)
    {
        // ...
    }
    catch (AggregateException ex) when (ex.InnerException is SomeOtherException)
    {
        // ...
    }
    

    您也可以像在示例中那样使用一些 if 语句来捕获它们:

    try
    {
        // ...
    }
    catch (AggregateException ex)
    {
        if (ex.InnerException is UserNotFoundException)
        {
            // ...
        }
        else if (ex.InnerException is SomeOtherExeption)
        {
            // ...
        }
    }
    

    【讨论】:

    • 太棒了!非常感谢,这让我非常清楚!
    猜你喜欢
    • 2016-09-08
    • 2017-09-18
    • 1970-01-01
    • 2017-07-10
    • 2016-12-07
    • 1970-01-01
    • 2021-02-15
    • 2014-05-17
    • 2018-09-24
    相关资源
    最近更新 更多