使用HandleErrorAttribute处理异常
ASP.NET MVC 默认提供了一个异常过滤器HandleError特性,使用该特性可以极为方便的捕捉并处理控制器和操作抛出的异常,也可以将此特性注册为全局异常过滤器从而捕捉项目中的所有异常。如果想要简单的消灭错误黄页(错误详细页),使用HandlerErrorAttribute是不错的选择!
本文演示项目下载地址:GlobalExceptionHandle-By-HandleErrorAttribute.zip,项目使用的VS2013和ASP.NET MVC 5框架,项目中也拷贝了HandleErrorAttribute的源码以供参考。
HandleErrorAttribute初步使用
使用HandleErrorAttribute处理异常很简单,首先要开启Web.config配置文件中的自定义错误,因为HandleError特性是依赖自定义错误的,customErrors的Mode必须要设置为On或RemoteOnly:
<customErrors mode="On" defaultRedirect="~/Error/Index"></customErrors>
到了这里基本上就成功启用了异常过滤器,因为VS2013新建的ASP.NET MVC 5项目默认将HandleError注册为全局异常过滤器,只要项目中的控制器和操作方法有抛出异常,默认就会被HandleError特性捕获,从而跳转到默认的错误详细页面~/Views/Shared/Error.cshtml。打开项目下App_Start的FilterConfig类(全局过滤器配置类),可以看到已经被注册的HandleErrorAttribute类:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
//如果要更改默认的错误视图,需要设置View属性
//filters.Add(new HandleErrorAttribute() { View = "~/Views/Error/CustomHttpError.cshtml" });
}
}
备注:关于FilterConfig类,如果不清楚的朋友可以看这篇文章:ASP.NET MVC 5 学习笔记之FilterConfig类
这里可以动态抛出一些异常来进行测试,在默认的Home控制器下复制如下代码:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
/// <summary>
/// 抛出HTTP 500
/// </summary>
/// <returns></returns>
public ActionResult ThrowHttp500()
{
throw new HttpException(500, "服务器错误");
}
/// <summary>
/// 抛出HTTP 404
/// </summary>
/// <returns></returns>
public ActionResult ThrowHttp404()
{
throw new HttpException(404, "页面未找到");
}
/// <summary>
/// 抛出未引用对象异常
/// ,此处单独使用HandleError特性
/// ,并指定异常类型及响应视图
/// </summary>
/// <returns></returns>
[HandleError(ExceptionType = typeof(NullReferenceException),View="CustomError")]
public ActionResult ThrowNullReferenceException()
{
throw new NullReferenceException();
}
/// <summary>
/// 引发输入字符串的格式不正确异常
/// ,此处指定了响应的错误页面
/// ,由于是不同的控制器所以要完整的相对路径
/// </summary>
/// <returns></returns>
[HandleError(View = "~/Views/Error/CustomHttpError.cshtml")]
public ActionResult ThrowFormatException()
{
string str = "";
int count = Convert.ToInt32(str);
return View("Index");
}
}
备注:记得添加对应的错误视图页和控制器,建议直接下载演示项目。
首页操作演示界面如下:
灵活运用HandleError特性
HandleError特性提供了许多属性,我们可以更加灵活的处理项目中抛出的异常。文档截图:
一般来说最常用的属性是View,Order和ExceptionType,至于AllowMultiple属性,除非业务有特殊要求,不然默认都是允许的。
自定义错误信息页面
先说View属性,设置此属性就可以自定义要跳转的错误视图页,否则一旦有异常抛出,默认会跳转到Error.cshtml这个页面,该页面路径为:~/Views/Shared/Error.cshtml。
设置View属性一定要注意路径问题,如果跳转的异常信息页面属于其他控制器,即控制器路由地址不同,那么一定要用完整的相对路径,否则引发二次异常:未找到视图**或其母版视图,或没有视图引擎支持搜索的位置。,比如下面代码(此声明是在Home控制器中,但是要跳转的错误页面则是在Error控制器中):
[HandleError(View = "~/Views/Error/CustomHttpError.cshtml")]
如果跳转的异常页面是属于当前控制器,或者是属于公共视图页的,就可以直接设置视图名称,代码如下:
[HandleError(View="CustomError")]
备注:CustomError是一个公共的自定义错误信息视图页面,另外公共视图页都是放在~/Views/Shared/这个路径下。
如果不想使用默认的Error.cshtml,想将所有的异常响应跳转到自定义的异常信息视图页,那么只要通过全局过滤器配置类FilterConfig,在注册HandleErrorAttribute时设置View属性即可,代码如下:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute() { View = "~/Views/Error/CustomHttpError.cshtml" });
}
}
同样要注意视图路径问题,其实这里最好使用公共视图页。这里额外说下Master属性,此属性可以指定要跳转的视图页的母板。基本上很少用,除非项目业务有需要,比如动态控制母板什么的,不然的话都是在视图中直接设置好的。
获取详细的异常信息
HandleErrorInfo类是HandleErrorAttribute默认提供的错误信息实体
可以通过此类获取引发异常的控制器和操作方法名称,以及通过获取Exception对象获取详细的错误内容。只要在对应的视图页中声明此类即可,演示代码:
@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = "自定义的公共错误页面";
}
@section styles{
<style type="text/css">
p {padding: 10px;}
</style>
}
<h2>自定义的公共错误页面</h2>
@if (Model != null)
{
<p class="bg-danger text-danger">
异常类型:@Model.Exception.GetType().Name
</p>
<p class="bg-danger text-danger">
触发异常的控制器:@Model.ControllerName
</p>
<p class="bg-danger text-danger">
触发异常的操作方法:@Model.ActionName
</p>
<p class="bg-danger text-danger">
错误信息:@Model.Exception.Message
</p>
<p class="bg-info text-info">
页面路径:~/Views/Shared/CustomError.cshtml
</p>
}
演示的视图截图:
针对异常类型
ExceptionType属性可以让HandleError针对某种异常类型做出处理,可以搭配View属性来使用,便于跳转到不同的异常信息页面,演示代码:
[HandleError(ExceptionType = typeof(NullReferenceException),View="CustomError")]
上面代码一旦捕获到NullReferenceException异常,就会跳转到CustomError视图页。注意一点,ExceptionType需要使用typeof转化异常类型。
关于过滤器的执行顺序
如果声明了多个HandleError异常过滤器,就需要使用到Order属性设置运行顺序。Order属性默认值为-1,也是最高优先级,正常来说整数值越大优先级越低,但是由于HandleError是继承于IExceptionFilter接口,所以优先级顺序是相反的,也就是说整数值越大,优先级也就越大,这里分享下官方文档的资料:
这里有两点需要注意:
- 如果Order属性小于-1会抛出异常,所以只能设置大于等于-1的整数值。
- 如果没有设置Order属性,由于默认值都是-1(即最高优先级),会导致过滤器的执行顺序变成无序随机。
使用HandleErrorAttribute的一些注意事项
虽然HandleError特性使用起来很简单,但是依然有很多需要注意很多地方,下面会详细的分析特性的局限性和一些缺点。
依赖于ASP.NET的自定义错误模块
如果customErrors mode="Off",则HandleError则无效,不对任何异常进行处理。
源码:
// If custom errors are disabled, we need to let the normal ASP.NET exception handler
// execute so that the user can see useful debugging information.
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
从源码中可以看到,当HttpContext.IsCustomErrorEnabled属性为false时(即未启用自定义错误),就不进行任何处理,直接return停止流程。
只能处理500服务器错误
像HTPP 404、401、503等错误代码,都是不处理的。源码可以很直接看出,只要不是500错误就直接return返回:
// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
// ignore it.
if (new HttpException(null, exception).GetHttpCode() != 500)
{
return;
}
因此除了500错误,其他错误只能通过自定义错误模块配置响应的页面:
<customErrors mode="On" defaultRedirect="~/Error/Index">
<error redirect="~/Error/NotFound" statusCode="404"/>
<error redirect="~/Error/NotFound" statusCode="400"/>
</customErrors>
只能跳转到视图
HandleError只提供了一个View属性,所以响应的异常信息页也只能是视图,其他的静态页面或者.aspx之类的都是无法进行跳转的,可以使用自定义异常过滤器实现此功能。
跳转的原理是通过设置ExceptionContext.Result属性:
filterContext.Result = new ViewResult
{
ViewName = View,
MasterName = Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
不利于SEO搜索引擎优化
这里涉及到部分SEO的知识,简单来说错误页面是使用302跳转,因此对搜索引擎抓取网站内容并不友好。如果是互联网行业的网站,考虑到SEO的问题还是不要用HandleErrorAttribute处理异常,类似企业系统的网站倒是十分适合使用。
至于应对的方法可以参考此文:ASP.NET MVC全局异常处理和捕获的思路
同时声明多个HandleError的效果
多个HandleError最终只有一个过滤器会执行,其他的过滤器会自动停止执行,至于是哪个过滤器执行则是依靠Order属性进行优先级确定,原理是使用ExceptionContext.ExceptionHandled属性进行判断,一旦该属性为true则表示当前抛出的异常已经被其他过滤器处理了,直接return停止余下的流程。
高级进阶之继承HandleErrorAttribute实现自定义功能
通过继承HandleErrorAttribute类创建新的异常处理特性,可以使我们扩展更多的自定义功能,比如记录错误日志、发送错误信息邮件等。继承后只要重写此类中的OnException方法即可实现功能,演示代码如下:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
/* 调用基类的OnException方法,实现基础的功能。
* 如果要完全的自定义,就不需要调用基类的方法
*/
base.OnException(filterContext);
/* 此处可进行记录错误日志,发送错误通知等操作
* 通过Exception对象和HttpException对象可获取相关异常信息。
* Exception exception = filterContext.Exception;
* HttpException httpException = new HttpException(null, exception);
*/
}
}
调用基类的OnException方法依然要注意HandleErrorAttribute类的一些限制,除非不使用基类的方法。继承后的新特性使用方法和HandleError一样,依然可以全局注册和局部使用。
如果需要完全自定义异常处理的功能,建议直接继承IExceptionFilter接口以实现功能,可以参考这篇文章:ASP.NET MVC实现IExceptionFilter接口编写自定义异常处理过滤器
参考资料分享
作者:十有三
出处:http://shiyousan.com/post/635838881238204198
欢迎转载本文,本文版权归作者所有,转载请声明出处或保留此段声明。^_^请尊重他人劳动成果,共建美好的网络环境。
使用HandleErrorAttribute处理异常的更多相关文章
- 日志记录类库log4net的使用总结
log4net是一个开源的日志记录类库,经过配置后可以自动抓取程序中的错误.异常信息,并写入磁盘,也可以在异常发生时执行其他指定的操作,比如:通知某人右键.写入数据库等.这里写个ASP.NET MVC ...
- MVC 使用HandleErrorAttribute统一处理异常
HandleErrorAttribute继承自FilterAttribute,且实现了IExceptionFilter接口. 属于AOP思想的一种实现,MVC的四大筛选器(权限,动作,结果,异常)中的 ...
- MVC4.0 利用HandleErrorAttribute和log4net实现记录异常日志功能
1.MVC4.0中HandleErrorAttribte已经帮我们处理了异常问题,当我们新建一个非空的MVC项目时候,在FilterConfig中会发现这样的代码 public class Filte ...
- MVC 全局异常过滤器HandleErrorAttribute
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- [Asp.net MVC]HandleErrorAttribute异常过滤器
摘要 在asp.net mvc中除了使用try...catch/finally来处理异常外,它提供了一种通过在Controller或者Action上添加特性的方式来处理异常. HandleErrorA ...
- MVC扩展Filter,通过继承HandleErrorAttribute,使用log4net或ELMAH组件记录服务端500错误、HttpException、Ajax异常等
□ 接口 public interface IExceptionFilter{ void OnException(ExceptionContext filterContext);} Except ...
- asp.net mvc HandleErrorAttribute 异常错误处理 无效!
系统未知bug,代码没有深究. 现象:filters.Add(new HandleErrorAttribute()); 使用了全局的异常处理过滤. HandleErrorAttribute 核心代码: ...
- HandleErrorAttribute只能处理httpStatusCode为500的异常(服务器异常)
HandleErrorAttribute源代码: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited ...
- 基于AOP的MVC拦截异常让代码更优美
与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...
随机推荐
- Oracle 学习笔记 12 -- 序列、索引、同义词
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/Topyuluo/article/details/24232449 数据库的对象包含:表.视图.序列. ...
- CloudFoundry V2 单机版离线安装(伪离线安装)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/wangdk789/article/details/30255763 之前安装CloudFou ...
- Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果. 手工装配依赖对象 手工装配依赖对象,在这种方式中又有两种编 ...
- 压力测试工具sysbench
sysbench是一个模块化.跨平台.多线程基准测试工具,主要用于测试不同系统参数下的数据库负载情况,本文主要介绍0.4版本的使用.sysbench主要用于以下性能测试: 文件I/O性能 调度 内存分 ...
- 数据库之ADO
ADO是一种跨多种语言的数据库访问技术. 在MFC里面微软公司将这些函数封装为以下几个类. 在VS2013版本的MFC中,这些类是如下定义的. CDaoDatabase Class:https://m ...
- Yii 2.x 和1.x区别以及yii2.0安装
知乎上有个类似的问题:http://www.zhihu.com/question/22924271/answer/23085751 大致思路不会变,开发流程变化也不是很大.有变化的是1.yii2带入的 ...
- python全栈开发从入门到放弃之socket网络编程基础
网络编程基础 一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务 ...
- GIL用C语言解决
执行一个单线程死循环程序,单核cpu占用直接100% while True: pass 执行一个双线程的死循环程序,cpu同样占用100% import threading #子线程死循环 def t ...
- Java基础知识陷阱(六)
本文发表于本人博客. 上次说了下equals跟==的问题,今天再来认识一下这个equals()跟hasCode().上次的代码如下: class Person{ public String name; ...
- HttpClient使用详解(转)
http://blog.csdn.net/wangpeng047/article/details/19624529