7.2WebApi2中的全局异常处理
现在在WebApi中还没有一种简单的方式去记录或者处理全局的异常。一些未处理的异常可以处理通过异常过滤器,但有大量的异常是异常过滤器不能处理的。例如:
- 从控制器的构造函数引发的异常。
- 从消息处理程序引发的异常。
- 在路由过程中引发的异常。
- 在响应内容序列化期间引发的异常。
我们需要提供简单、 一致的方式来记录和处理 (如果可能) 这些异常。
处理异常有两种方式,其中一种我们可以发送一个错误响应;另外一种我们可以在那里记录日志异常,举个例子就是引发异常是在响应流的内容时,在这个时候处理就太晚了,因为这时响应码,标题和部分响应内容已经在传输上了,所以我们只是中断连接发送响应消息。即使不能处理该异常,我们仍能记录异常日志,在那里我们可以检测到错误的情况下,返回相应的错误响应,如下所示:
1 public IHttpActionResult GetProduct(int id) 2 { 3 var product = products.FirstOrDefault((p) => p.Id == id); 4 if (product == null) 5 { 6 return NotFound(); 7 } 8 return Ok(product); 9 }
现有的选项
解决方案概述
我们提供两个用户可更换的服务, IExceptionLogger和 IExceptionHandler,来记录和处理未处理的异常。服务是很相似,但是也有两个主要区别 ︰
- 我们支持注册多个异常记录器,但只有一个单一的异常处理程序。
- 异常的记录器总是会调用,即使我们要中止连接。异常处理程序只会调用时我们仍然能够以选择要发送的响应消息。
这两种服务提供访问异常上下文包含异常检测到的点、 特别是HttpRequestMessage、 HttpRequestContext、 抛出的异常和异常源 (细节如下) 的相关信息。
设计原则
1.没有重大更改
因为在次要版本中,一个重要的制约因素影响的解决方案是,有没有重大的更改,或者键入合同或行为正在添加此功能。此约束排除我们想在现有车削成 500 反应异常的 catch 块做了一些清理。这额外的清理是我们可能会考虑后续的主要版本。如果这是重要的您在ASP.NET Web API 用户声音请投票.
2.保持一致性与 Web API 构建
Web API 的滤清器管道是一个伟大的方式来处理横切关注点的逻辑在特定操作、 控制器具体或全球范围内的应用灵活性。过滤器,包括异常筛选器,总是有行动和控制器的情况下,即使在全球范围内注册。合同有道理的筛选器,但它意味着异常筛选器,甚至全球范围的不是很好的适合一些异常处理情况下,如异常从消息处理程序,在没有行动或控制器的上下文存在。如果我们想要使用所筛选的异常处理提供灵活的范围,我们仍然需要异常筛选器。但如果我们需要处理异常控制器上下文之外,我们还需要一个单独的构造全全局错误处理 (东西没有控制器上下文和操作上下文约束)。
何时使用
- 异常的记录器是见到所有未处理的异常被 Web API 的解决方案。
- 异常处理程序是用于自定义所有可能响应未处理的异常被 Web API 的解决方案。
- 异常筛选器是最简单的解决方案,针对有关的具体行动或控制器子集未处理的异常处理。
服务详细信息
异常日志记录器和处理程序服务接口是简单的异步方法以各自的具体情况 ︰
1 public interface IExceptionLogger 2 { 3 Task LogAsync(ExceptionLoggerContext context, 4 CancellationToken cancellationToken); 5 } 6 7 public interface IExceptionHandler 8 { 9 Task HandleAsync(ExceptionHandlerContext context, 10 CancellationToken cancellationToken); 11 }
我们也为这两种接口提供基类,这些类。重写核心 (同步或异步) 方法是登录或在推荐处理所需的全部时间。日志记录, ExceptionLogger
基类将确保核心测井方法只一次呼吁每个例外 (即使它后来传播进一步向上调用堆栈和再次抓住)。ExceptionHandler
基类将调用核心处理方法仅用于顶部的调用堆栈,忽略遗留的嵌套的 catch 块的异常情况。(下面附录中的这些基类简化的版本)。
IExceptionLogger
和IExceptionHandler
收到异常有关的信息通过ExceptionContext
.
1 public class ExceptionContext 2 { 3 public Exception Exception { get; set; } 4 5 public HttpRequestMessage Request { get; set; } 6 7 public HttpRequestContext RequestContext { get; set; } 8 9 public HttpControllerContext ControllerContext { get; set; } 10 11 public HttpActionContext ActionContext { get; set; } 12 13 public HttpResponseMessage Response { get; set; } 14 15 public string CatchBlock { get; set; } 16 17 public bool IsTopLevelCatchBlock { get; set; } 18 }