ASP.NET Core Exception middelware 每层嵌套异常

ASP.NET Core Exception middelware nesting exceptions for each layer

我创建了一个全局异常处理程序中间件来捕获我所有的自定义异常。

在我的 DAL 中抛出异常时,我希望中间件能够将其捕获为与抛出的类型相同的异常。

// API
[HttpGet]
[Route("api/users")]
public IActionResult Get(int id)
{
    var user = _userService.GetById(id);
    return Ok(user);
}

// Repository
public async Task<List<User>> GetById(int id)
{
    throw new EntityNotFoundException("code", "message");
    // .. return user 
}

// Exception handler
public async Task Invoke(HttpContext httpContext)
{
    try
    {
        await _next(httpContext);
    }
    catch (Exception ex) // ex is of type JsonSerializationException 
    {
        if (ex is EntityNotFoundException)
        {
            // Handle exception
        }
    }
}

在上面的示例中,异常已被处理,但属于 JsonSerializationException 类型,其中包含类型为 System.AggregateException 的 InnerException,后者包含另一个类型为 EntityNotFoundException 的 InnerException。

似乎异常嵌套在它传递的每一层中(DAL > 服务 > API)。我怎样才能避免这种情况,以便我可以将异常捕获为原始类型?

you provided looks good but it lacks one important thing, which is single responsibility.

ASP.NET Core 有一个更好的方法,它使用 exception filters,它也可以全局注册并且可以为每个 custom-exception 甚至未处理的异常编写。

样本:

public class EntityNotFoundExceptionFilter : IExceptionFilter
{
   public EntityNotFoundExceptionFilter(// some dependencies that u want to inject)
   {
       ...
   }

   public void OnException(ExceptionContext context)
   {
      if (!(context.Exception is EntityNotFoundException))
      {
          return;
      }

      context.ExceptionHandled = true;
      context.Result = new NotFoundObjectResult // will produce 404 response, you can also set context.HttpContext.Response.StatusCode based on your exceptions statuscode and return an ObjectResult instead
      {
         context.Exception.Message
      }
   }
}

现在在你的Startup.cs中的ConfigureServices(...)函数中添加下面的

public void ConfigureService(IServiceCollection services)
{
    ...
    services.AddMvc(options => 
    {
        ...
        options.Filters.Add(typeof(EntityNotFoundExceptionFilter));
        ...
    }
    ...
}

你最终会写很多过滤器,但这是一种更简洁的方法,这就是应该使用 asp.net-core filterpipeline 的方式 + 这将起作用:)

我不是 100% 确定为什么在您当前的实现中有这么多异常,但我的猜测是 asp.net 尝试 return 异常然后无法序列化它和类似的东西.

编辑:

我创建了一个最小示例,可以在克隆项目后找到 here. Just access the url via http://localhost:58741/api/some