asp.net web api 异常捕获
1 向客户端发送错误消息
使用throw new HttpResponseException()向客户端抛出错误信息。
HttpResponseException包含两个重载的构造函数,其中一个是构造函数参数类型为HttpResponseMessage,通过其设置状态码,错误消息短语以及消息体内容来向客户端抛出比较详细的错误信息。另一个参数类型为HttpStatusCode,只能设定状态码。
2自定义异常过滤器
扩展IExceptionFilter来定义异常过滤器。异常过滤器不会捕获类型为HttpResponseException的异常,下面的异常也无法被异常过滤器捕获:
1)controller构造器抛出的异常
2)消息处理器抛出的异常
3)路由过程中抛出的异常
4)响应内容序列化与反序列化过程中抛出的异常
代码示例:
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception!=null)
{
LogHelper.LogError(context.Exception);
}
}
}
3 扩展ExceptionHandler和ExceptionLogger
扩展ExceptionHandler可以捕获大部分异常,包括一些无法被异常过滤器捕获的异常。但是HttpResponseException类型的异常不会被捕获。
示例代码:
/// <summary>
/// 自定义的异常处理程序
/// </summary>
public class GlobalExceptionHandler : ExceptionHandler
{
/// <summary>
/// 处理异常
/// </summary>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task HandleAsync(ExceptionHandlerContext context,CancellationToken cancellationToken)
{
if (!ShouldHandle(context))
{
return Task.FromResult(0);
}
context.Result = new ErrorResult
{
Request = context.ExceptionContext.Request,
Content = "呀! 有异常,请联系管理员"
};
return Task.FromResult(0);
}
/// <summary>
/// 判断是否应该处理
/// 后期扩展,重写方法可过滤掉不需处理的异常
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool ShouldHandle(ExceptionHandlerContext context)
{
return true;
}
private class ErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
public class GlobalExceptionLogger : ExceptionLogger
{
public override Task LogAsync(ExceptionLoggerContext context,CancellationToken cancellationToken)
{
if (!ShouldLog(context))
{
return Task.FromResult(0);
}
if (context.Exception != null)
{
string msg = ClientInfoAnalysis.GetClientInfo();
LogHelper.LogError(context.Exception, msg);
}
return Task.FromResult(0);
}
/// <summary>
/// 判断是否应记录异常
/// 后期重写此方法,可过滤掉不需要记录的异常信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool ShouldLog(ExceptionLoggerContext context)
{
if ((context.Exception is System.Web.HttpException))
{
return false;
}
return true;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 加载log4net配置文件
LogConfigLoading.Load(AppSettings.Log4netPathForWeb);
// 加载Web API服务
config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(AppSettings.ServicesLocation));
// 全局异常信息处理
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
// 全局异常记录
config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());
}
}
4某些异常无法被捕获的异常
问题描述
对于在服务加载过程中的异常,无法通过异常过滤器,即实现了System.Web.Http.Filters.IExceptionFilter接口的过滤器来捕获,也不能通过注册ExceptionLogger来达到目的。解决方法如下:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
try
{
config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));
}
catch (Exception ex)
{
LogHelper.Error(ex);
}
//其他代码
}
}
其中ServiceAssembliesResolver为:
public class ServiceAssembliesResolver : DefaultAssembliesResolver
{
//服务插件路径
private string path;
public ServiceAssembliesResolver(string path):base()
{
this.path = path;
}
public override ICollection<Assembly> GetAssemblies()
{
//获得已有的服务
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
//初始化
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
//加载每一个服务插件
foreach (string file in Directory.GetFiles(path, "*.dll"))
{
var controllersAssembly = Assembly.LoadFrom(file);
assemblies.Add(controllersAssembly);
}
return assemblies;
}
}
但上述方法很可能不起作用,根本原因在于将config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));放入try-catch块中,若ServiceAssembliesResolver在实例化的时候不抛出异常,而是当调用GetAssemblies时抛出异常(例如服务插件存储文件夹被删除),此时无法记录异常。那么问题就在于GetAssemblies方法何时被调用,通过跟踪代码发现Register中的所有代码都执行完成才会加载服务。解决办法是在ServiceAssembliesResolver.GetAssemblies中捕获异常并记录下来。
- FindBugs详解
- Java杂项
- android SurfaceView绘制实现原理解析
- AbstractQueuedSynchronizer实现示例
- PyQt的一个UI单元测试框架思路
- Spring Cloud Zuul实现动态路由
- android应用资源预编译,编译和打包全解析
- Python优雅地dumps非标准类型
- html5标签基础
- 彻底搞懂Gradle、Gradle Wrapper与Android Plugin for Gradle的区别和联系
- 社会化分享
- Android真机安装sqlite3的方法
- 二次元世界的Linux—东方Project之B站掠影
- 带三方登录(qq,微信,微博)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- VBA编写Ribbon Custom UI编辑器04——解析xml
- VBA编写Ribbon Custom UI编辑器05——转换结构体XML
- MySQL 8.0.19 Linux平台安装 Part 1
- MySQL 8.0.19 Linux平台安装 Part 2
- 使用XtraBackup备份MySQL 8.0 Part 1 xtrabackup 8.0 安装
- 10个解放双手的 IDEA 插件,少些冤枉代码!
- 二叉树的 4 种遍历方式,你会多少?
- 【C++简明教程】Python和C++指定元素排序比较
- PG原生解码工具pg_recvlogical的使用-在脑裂时帮我们找回丢失的数据
- 使用XtraBackup备份MySQL 8.0 Part 4 对数据库进行全备
- 介绍一下java的基本类型; 每种数据类型的位数(答错了,太菜了)
- 可读代码编写炸鸡十一 - 小黄鸭从你的心里游到脑子里
- 大数据技术之Hadoop(HDFS)第1章 HDFS概述
- Mongodb多键索引之数组
- 使用XtraBackup备份MySQL 8.0 Part 5 对全备份进行恢复