【问题标题】:ASP.NET Core Exception middelware nesting exceptions for each layerASP.NET Core Exception 中间件每层嵌套异常
【发布时间】:2018-08-20 21:23:50
【问题描述】:

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

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

// 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)。如何避免这种情况,以便将异常捕获为原始类型?

【问题讨论】:

  • 您能否提供更多关于这是什么类型的处理程序的代码?似乎没有实现 IExceptionFilter 接口,是吗(看起来像一个动作过滤器)?也没有正确理解你 DAL 抛出异常然后 Service 也抛出异常?
  • 只有 DAL 抛出异常。据我从其他示例中可以看出,异常处理程序不需要实现 IExceptionFilter:stackoverflow.com/questions/38630076/…(查看已接受的答案)
  • 是的,您也可以实现过滤器属性,但您的过滤器中缺少 OnException 函数。你的实现不是动作过滤器吗?
  • 它不是一个过滤器,它是一个自定义的中间件。使用过滤器是否能够将异常捕获为抛出的类型,还是不会产生影响?
  • 为您的问题添加了答案,希望对您有所帮助。

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


【解决方案1】:

您提供的example 看起来不错,但缺少一个重要的东西,那就是single responsibility

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

示例:

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 尝试返回异常,然后无法序列化它和类似的东西。

编辑:

我创建了一个可以在here 找到的最小示例。克隆项目后通过http://localhost:58741/api/some访问url。

【讨论】:

  • 我尝试使用过滤器,但它不起作用。 OnException 方法仅在控制器中抛出异常时才捕获该异常。当在 DAL 之类的另一层中抛出时,它会再次导致 Newtonsoft.Json.JsonSerializationException(没有被 ExceptionFilter 捕获)。
  • 肯定有什么东西导致了更多的错误。我建议您检查调用堆栈,看看是什么引发了更多异常。请稍等片刻,制作一个您可以使用的最小示例,看看是什么导致了您的问题以及为什么它不起作用。
  • 用可以下载和运行的示例更新了帖子。如果您需要更多帮助,请同时提供您的 Startup-Class 和潜在的中间件。如果您不介意将整个项目托管在 git 上,我将看看是什么导致了问题。
  • 成功了!很抱歉给您带来不便,这是一个异步问题。
猜你喜欢
  • 2014-03-19
  • 1970-01-01
  • 2019-11-10
  • 2013-09-11
  • 2021-07-13
  • 2021-08-06
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
相关资源
最近更新 更多