Web API 异常处理
Web Api的ExceptionFilter只能截获并处理Action执行过程中发生的异常,在Action执行过程之外如果出现异常,ExceptionFilter是无能为力的。
这些异常包括:
1、 Controller构造方法中出现的异常
2、 MessageHandlers中出现的异常
3、 路由过程中出现的异常
4、 Body在序列化/反序列化过程中出现的异常
由此可以看出,ExceptionFilter只能解决ApiControler成功实例化后并执行Action期间出现的异常;为了解决这一个问题,在WEB API中除了ExceptionFilter外还引入了两个针对异常记录、处理的扩展点:
IExceptionLogger 和IExceptionHandler。
而这两个扩展是作为Web API的管道组件进行注册管理的,并且,他们有不同的分工:
IExceptionLogger作为异常日志记录组件,负责异常发生后的日志记录,他贯穿于整个Web API的生命周期中,在Web API框架里,任何一个请求周期中出现任何一个未被捕获/处理的异常都会首先进入这个异常日志记录管道进行异常Log记录,在Web API中可以注册多个IExceptionLogger实例负责不同的异常处理。
IExceptionHandler作为异常处理组件,负责异常发生后的处理工作,他处于异常处理管道的最末端,当IExceptionLogger组件进行一场记录完毕、没有相关的ExceptoinFilter进行异常处理时,才会最终调用ExceptionHandler进行异常处理,在Web API中,有且仅有一个ExceptionHandler进行异常的处理。
在Web API框架中给出了两个基类:ExceptionLogger和ExceptionHandler,在使用ExceptionLogger基类时,他提供了ShouldLog虚方法,该方法在基类中被调用,其作用在于避免同一个异常被同一个ExceptionLogger实例重复记录(如当后续的管道中该异常又被抛出,或者同一个ExceptionLogger对象不小心被注册了两次就会出现重复记录的可能)我们也能复写ShouldLog方法加入我们自己的异常记录判断逻辑以针对不同的场景进行不同的ExceptionLogger调用。如果有兴趣可以反编译一下ExceptionLogger基类看看,他使用了显示接口实现,挺有意思的一个技巧。下面我们来看一个ExceptionLogger使用的例子:

public class ErroLogger : ExceptionLogger
{
public async Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
{
var sb = new StringBuilder();
//获取Log组件
ILogger log = LogManager.GetCurrentClassLogger(); var request = context.Request; sb.AppendLine("URL:");
//获取URL
var url = request.RequestUri.ToString();
sb.AppendLine(url); log.Error(context.Exception,sb.ToString(),"");
} public override bool ShouldLog(ExceptionLoggerContext context)
{
return context.Exception is DemoException && base.ShouldLog(context);
}
}

在这个例子中,我们重写了ShouldLog,保证了这个ExceptionLogger只记录DemoException这个类型的异常,并且也调用了基类方法,保证不会重复记录同一个异常。在LogAsync方法中,我通过Log组件记录了导致异常的请求URL,也记录了异常信息。
接下来我们要对这个组件进行注册:
在App_Start/WebApiConfig.cs文件中的Register方法中写入
config.Services.Add(typeof(IExceptionLogger),new ErroLogger());
这样,一个针对DemoException的异常记录组件就开发完成并注册完成了,当Web API执行管道中出现未处理的DemoException异常,均会调用则个组件进行记录。
接下来我们来写一个ExceptionHandler,在整个Web API框架中,ExceptionHandler只能提供一个实例,与ExceptionLogger一样,我们可以继承ExceptionHandler基类来简化异常处理,在ExceptionHandler中也提供了ShouldHandle方法来判断该异常是否应该处理,避免重复处理管道中其他环节重复抛出的异常。我们也同样提供一个例子:

public class ErrorHandler : ExceptionHandler
{
public override async Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context.Exception is DemoException)
{
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.BadRequest,new {Message=context.Exception.Message}));
}
else
{
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,new {Message = "服务器已被外星人绑架"}));
}
}
}

在这个例子中,我们判断了异常的类型,并根据不同的异常返回客户端不同的响应内容和不同的HTTP状态码。
然后在配置中注册这个异常处理模块,在App_Start/WebApiConfig.cs文件中的Register方法中写入
config.Services.Replace(typeof(IExceptionHandler),new ErrorHandler());
这样就替换了系统默认的ExceptionHandler,可以使用我们自定义的Handler进行异常的处理了。
在异常记录、处理过程中,我们都碰到相应的异常上下文参数,我们能通过这个参数获取当前请求的上下文,获取请求、响应(小心有时会为空哦)、捕获到该异常的catch块信息等内容,我们可以利用这些信息更好地描述、记录、处理异常。
到这里ExceptionLogger组件和ExceptionHandler组件简单的开发就完成了。在开发的过程中我们可以看到,ExceptionLogger负责了全局的异常记录,在Web API框架管道下出现未处理的异常ExceptionLogger都会进行捕获、记录。而ExceptionHandler和ExceptionFilter功能是有重叠的,那何时使用ExceptionHandler何时使用ExceptionFilter呢?我们可以将两者的区别列出如下的表格:
|
ExceptionFilter |
ExceptionHandler |
|
|
作用域 |
Controller、Action |
全局 |
|
实例个数 |
无限制 |
全局唯一 |
|
作用条件 |
Controller实例化成功之后 |
Web API成功加载之后 |
经过上面的表我们可以看出,如果处理颗粒度细致到Controller、Action级别时,ExceptionFilter处理起来会更得心应手,他已经能精确定位到某个Action,然后可以针对当前Action做定制开发。而ExceptionHandler作用域远大于ExceptionFilter,他处理全局更有优势。
Web API 异常处理的更多相关文章
- Asp.Net Web API 2第七课——Web API异常处理
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文主要来讲解Asp.Ne ...
- WEB API异常处理
当一个web api抛出一个异常后 此异常会被转化成一个HTTP响应 错误代码为500的服务错误 但是如果你不想让客户端看到500的错误码 你也可以自定义错误码 如下代码当用户输入的ID没有与之相关的 ...
- ASP.NET mvc4 WEB API异常处理
当一个web api抛出一个异常后 此异常会被转化成一个HTTP响应 错误代码为500的服务错误 但是如果你不想让客户端看到500的错误码 你也可以自定义错误码 如下代码当用户输入的ID没有与之相关的 ...
- ASP.NET Web API 异常处理 HttpResponseException 以及Angularjs获取异常信息并提示
一.HttpResponseException 如果一个Web API控制器抛出一个未捕捉异常,默认地,大多数异常都会被转化成一个带有状态码“500 – 内部服务器错误”的HTTP响应.HttpRes ...
- Web API系列(三) 异常处理
在上一篇教程中我为大家介绍了Web API中Filter的开发使用,其中讲到ExceptionFilter时留了一个坑:ExceptionFilter只能截获并处理Action执行过程中发生的异常,在 ...
- ASP.NET Web API系列教程目录
ASP.NET Web API系列教程目录 Introduction:What's This New Web API?引子:新的Web API是什么? Chapter 1: Getting Start ...
- Web API 2
Asp.Net Web API 2 官网菜鸟学习系列导航[持续更新中] 前言 本来一直参见于微软官网进行学习的, 官网网址http://www.asp.net/web-api.出于自己想锻炼一下学 ...
- ASP.NET Web API系列教程(目录)(转)
注:微软随ASP.NET MVC 4一起还发布了一个框架,叫做ASP.NET Web API.这是一个用来在.NET平台上建立HTTP服务的Web API框架,是微软的又一项令人振奋的技术.目前,国内 ...
- [转]ASP.NET Web API系列教程(目录)
本文转自:http://www.cnblogs.com/r01cn/archive/2012/11/11/2765432.html 注:微软随ASP.NET MVC 4一起还发布了一个框架,叫做ASP ...
随机推荐
- BZOJ.5287.[AHOI HNOI2018]毒瘤(虚树 树形DP)
BZOJ LOJ 洛谷 设\(f[i][0/1]\)表示到第\(i\)个点,不选/选这个点的方案数.对于一棵树,有:\[f[x][0]=\prod_{v\in son[x]}(f[v][0]+f[v] ...
- 解决linux环境mysql的sql语句严格区分大小写问题
在Windows环境下,mysql数据库的sql语句是不区分字母大小写的,但是程序移植到linux环境中,就会造成某些大小写不一致的语句执行失败,解决方法如下: 首先打开/etc/mysql/my.c ...
- STM32点亮闪烁LED灯
详解请看其他博客: http://www.cnblogs.com/whik/p/6672730.html http://www.51hei.com/bbs/dpj-38605-1.html /*本程序 ...
- C++知识点:拷贝构造函数例子
//拷贝构造函数: //函数参数传递时调用一次拷贝构造函数,给对象赋值时调用一次拷贝构造函数,对象作为参数传递后会被及时销毁. #include <fstream> #include &l ...
- linux查看tomcat安装路径
#查看tomcat安装路径 sudo find / -name *tomcat*
- yii创建控制台命令
创建控制台命令程序1.控制台命令继承自 yii\console\Controller控制器类2.在控制器类中,定义一个或多个动作,动作与控制台子命令相对应3.在动作方法中实现业务需求的代码 运行控制台 ...
- yii2 用 bootstrap 给元素添加背景色
使用 bootstrap 给元素添加背景色 1.bootstrap 官网:http://getbootstrap.com/ 2.bootstrap 中文官网:http://v3.bootcss.com ...
- 用node搭建本地服务环境
const express = require('express'); const path = require('path'); const request = require('request') ...
- JS自学笔记03
JS自学笔记03 1.函数练习: 如果函数所需参数为数组,在声明和定义时按照普通变量名书写参数列表,在编写函数体内容时体现其为一个数组即可,再传参时可以直接将具体的数组传进去 即 var max=ge ...
- xinetd服务
xinetd(eXtended InterNET services daemon) 一.xinetd的功能介绍: xinetd提供类似于inetd+tcp_wrapper的功能,但是更加强大和安全.它 ...