我们说我有一个Web API服务,它调用我的用户服务来返回用户个人资料信息等。
UserProfileService
可以抛出UserNotFoundException
。抛出时,它被序列化并作为AggregateException
中的内部异常发送,可以在调用方法中捕获。此服务使用Service Fabric的服务远程处理进行RPCing。
我的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);
}
}
这里有几个问题:
天真地我做这样的事情:
try { /* ... */ } catch (AggregateException ae)
{
foreach(var e in ae.InnerExceptions)
{
if (e is UserNotFoundException)
{
return NotFound();
}
}
return errorResponse ?? StatusCode(StatusCodes.Status500InternalServerError);
}
但问题是,如果有多个例外,只有一个会赢得#34;。并且,我相信 - 尽管无法保证,最早添加的Exception
将具有优先权,因为它们在InnerExceptions
中的索引较低。我在想这个,这个解决方案会没问题吗?我抛出自定义异常的唯一一次是当我知道它们应该抛出时,当然?
这引出了我的另一个问题:
AggregateException
。当你Task a
召唤Task b
来调用Task c
,c
投注,b
不投掷,{{1} }抛出,你得到包含a
和a
例外的汇总异常?
答案 0 :(得分:2)
我会向后回答你的问题:
2)AggregateException
有一个contructor,允许IEnumerable<Exception>
作为参数。这是它如何包含多个内部异常。这意味着您的聚合异常不会包含多个内部异常,除非您明确抛出具有多个内部异常的AggregateException
。假设您有Task a
来电Task b
来电Task c
。如果c
引发了一个未在a
或b
中捕获的异常,a
会抛出AggregateException
内部AggregateException
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)
{
// ...
}
}
答案 1 :(得分:1)
我建议在所有相关类中抛出异常,并且只捕获Web服务中的异常,向Web服务调用者报告一条错误消息。保持异常处理尽可能简单。
改写:如果在任何代码中出现问题,只需throw new Exception()
,其中一个字符串表示发生了什么以及在哪里。您try/catch
所在的唯一地点位于[httpget] Get()
。
如果你真的知道你在做什么,你可以实现序列化的异常,但是你不会在这里问这个: - )