MVC异常过滤器
MVC过滤器
- 一般的过滤器执行顺序
- IAuthorizationFilter->OnAuthorization(授权)
- IActionFilter ->OnActionExecuting(行为)
- Action
- IActionFilter ->OnActionExecuted(行为)
- IResultFilter ->OnResultExecuting(结果)
- View
- IResultFilter ->OnResultExecuted(结果)
- *IExceptionFilter ->OnException(异常),此方法并不在以上的顺序执行中,有异常发生时即会执行,有点类似于中断
- 当同时在Controller和Action中都设置了过滤器后,执行顺序一般是由外到里,即“全局”->“控制器”->“行为”
- Controller->IAuthorizationFilter->OnAuthorization
- Action ->IAuthorizationFilter->OnAuthorization
- Controller->IActionFilter ->OnActionExecuting
- Action ->IActionFilter ->OnActionExecuting
- Action
- Action ->IActionFilter ->OnActionExecuted
- Controller->IActionFilter ->OnActionExecuted
- Controller->IResultFilter ->OnResultExecuting
- Action ->IResultFilter ->OnActionExecuting
- Action ->IResultFilter ->OnActionExecuted
- Controller->IResultFilter ->OnActionExecuted
- 因为异常是从里往外抛,因次异常的处理顺序则刚好相反,一般是由里到外,即“行为”->“控制器”->“全局”
- Action ->IExceptionFilter->OnException
- Controller->IExceptionFilter->OnException
系统自带的异常处理
我们习惯使用的过滤器,要么是为Action加上Attribute,要么就是为Controller加上Attribute。上面所说的全局过滤器是怎么回事呢?先看看Gloabal里的代码:
protected void Application_Start(){
//注册Area AreaRegistration.RegisterAllAreas();
//注册过滤器 RegisterGlobalFilters(GlobalFilters.Filters);
//注册路由 RegisterRoutes(RouteTable.Routes);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
由上可知,在应用程序启动的时候就已经注册了全局过滤器,HandleErrorAttribute就是系统自带的异常过滤器。在这注册的全局过滤器,可以不用到每个Controller或者是每个Action去声明,直接作用于全局了,即可以捕捉整个站点的所有异常。看看它的源码是怎么处理异常的:
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
{
Exception innerException = filterContext.Exception;
if ((new HttpException(null, innerException).GetHttpCode() == ) && this.ExceptionType.IsInstanceOfType(innerException))
{
string controllerName = (string) filterContext.RouteData.Values["controller"];
string actionName = (string) filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
ViewResult result = new ViewResult {
ViewName = this.View,
MasterName = this.Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
filterContext.Result = result;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = ;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
}
HandleErrorAttribute的异常处理逻辑里,生成了一个HandleErrorInfo类的Model,并设置返回的结果为一个新生成的ViewResult。这个视图默认的ViewName是Error,对应于Share文件夹里的Error视图。而自带的Error视图没有用到HandleErrorInfo的Model,因此公开的信息也不是很多,可以根据具体的需求改造一下。例如:
@model HandleErrorInfo
<br />
<div class="container">
<div class="alert alert-error">
<h4> Exception:</h4> <br />
<p>
There was a <b>@Model.Exception.GetType().Name</b> while rendering <b>@Model.ControllerName</b>'s<b>@Model.ActionName</b> action.</p> <p> @Model.Exception.Message
</p>
</div>
<div class="alert"> <h4> Stack trace:</h4> <br /> <pre>@Model.Exception.StackTrace</pre> </div>
</div>
这个过滤器要能起效,还需要在配置文件中配置一下:<customErrors mode="On" />
自定义的异常统一处理
在实现异常的统一处理之前,先来明确一下需求:
- 站点所有页面在异常发生后,均需要记录异常日志,并转向错误提示页面(异常内容的详略程度由具体需求决定)
- 所有返回JSON数据的异步请求,不但需要记录异常日志,而且需要向客户端返回JSON格式的错误信息提示,而不是转向错误提示页面(异步请求也不可能转向错误提示页面)
- 采用AOP思想,将异常处理解耦
- 尽量精简声明Attribute的重复代码
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class JsonExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
//返回异常JSON
filterContext.Result = new JsonResult
{
Data = new { Success = false, Message = filterContext.Exception.Message }
};
}
}
}
这里也不需要设置filterContext.ExceptionHandled = true,否则在LogExceptionAttribute处理时,因为 !filterContext.ExceptionHandled 的判断条件,LogExceptionAttribute的逻辑不会执行,也就不会记录异常日志了。
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class LogExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
string msgTemplate = "在执行 controller[{0}] 的 action[{1}] 时产生异常";
LogManager.GetLogger("LogExceptionAttribute").Error(string.Format(msgTemplate, controllerName, actionName), filterContext.Exception);
} if (filterContext.Result is JsonResult)
{
//当结果为json时,设置异常已处理
filterContext.ExceptionHandled = true;
}
else
{
//否则调用原始设置
base.OnException(filterContext);
}
}
}
修改全局过滤器:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleError2LogAttribute());//全局的日志异常过滤器
//filters.Add(new HandleErrorAttribute());
}
[HttpPost]
[JsonException]
public JsonResult Add(string ip, int port)
{
... //处理逻辑
return Json(new { Success = true, Message = "添加成功" });
}
MVC异常过滤器的更多相关文章
- MVC异常过滤器 (错误页)
控制器 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syste ...
- ASP.NET Core 中间件 自定义全局异常中间件以及 MVC异常过滤器作用
中间件是一种装配到应用管道以处理请求和响应的软件. 每个组件: 选择是否将请求传递到管道中的下一个组件. 可在管道中的下一个组件前后执行工作. 请求委托用于生成请求管道. 请求委托处理每个 HTTP ...
- MVC异常过滤器在三种作用范围下的执行顺序
对于一般过滤器(即:除了IExceptionFilter ),当同时在Controller和Action中都设置了同一个过滤器后(例如IActionFilter),执行顺序一般是由外到里,即“全局”- ...
- MVC与WebApi中的异常过滤器
一.MVC的异常过滤器 1.自定义MVC异常过滤器 创建一个类,继承HandleErrorAttribute即可,如果不需要作为特性使用直接实现IExceptionFilter接口即可, 注意,该 ...
- MVC异常日志生产者消费者模式记录(异常过滤器)
生产者消费者模式 定义自己的异常过滤器并注册 namespace Eco.Web.App.Models { public class MyExceptionAttribute : HandleErro ...
- MVC 全局异常过滤器HandleErrorAttribute
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- asp.net core MVC 全局过滤器之ExceptionFilter异常过滤器(一)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter异常过滤器(一) asp.net cor ...
- 笨鸟先飞之ASP.NET MVC系列之过滤器(06异常过滤器)
概念介绍 异常过滤器主要在我们方法中出现异常的时候触发,一般我们用 异常过滤器 记录日志,或者在产生异常时做友好的处理 如果我们需要创建异常过滤器需要实现IExceptionFilter接口. nam ...
- MVC教程九:异常过滤器
我们平常在程序里面为了捕获异常,会加上try-catch-finally代码,但是这样会使得程序代码看起来很庞大,在MVC中我们可以使用异常过滤器来捕获程序中的异常,如下图所示: 使用了异常过滤器以后 ...
随机推荐
- grep的使用【转】
grep的作用是显示匹配一个或多个模式的文本行.时常会作为管道(|)的第一步,以便对匹配的数据作进一步处理.grep常用于查找和替换文本的.在传统上,grep有3个版本:grep.egrep(扩展gr ...
- C# winform压缩文件夹带进度条
注意:用了开源的CL.IO.Zip库 pbYSJD是进度条的控件名 btnImport是按钮控件名,当压缩结束之后,使按钮处于激活状态,否则无法点击按钮. /// <summary> // ...
- DBCA创建数据库ORA-01034 ORACLE not available
SYMPTOMS 在利用dbca创建数据库时,当设置完毕全部參数.開始装时 跑到2% 就报错 ORA-01034 ORACLE not available, 例如以下图 watermark/2/tex ...
- ADT+NDK搭建jni编译环境
jni是android调用C++编写的库的接口.C++和java的差别不在此文的讨论范畴,另外这里也仅仅是记录下.怎样搭建好开发环境. 首先是下载ADT包和NDK包. ADT包包括了eclipse.所 ...
- Unity 3D本地公布WebPlayer版时"Failed to download data file"解决方式
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlzZW55YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- ASP.NET Identity 角色管理(Roles)
当我们使用ASP.NET 4.5创建模板项目时,会发现模板只提供了ApplicationUserManager用于用户的登录注册.修改.设置等,而没有提供与用户角色相关的代码,对此就需要我们自己手动的 ...
- NetHogs---按进程或程序实时统计网络带宽使用率。
NetHogs是一个开源的命令行工具(类似于Linux的top命令),用来按进程或程序实时统计网络带宽使用率. 来自NetHogs项目网站: NetHogs是一个小型的net top工具,不像大多数工 ...
- 紫书 例题 10-16 UVa 12230(数学期望)
感觉数学期望的和化学里面求元素的相对原子质量的算法是一样的 就是同位素的含量乘上质量然后求和得出 这道题因为等待时机是0到2*l/v均匀分配的,所以平均时间就是l/v 再加上过河的l/v, 最后加上步 ...
- ArcGIS api for javascript——地理处理任务-计算一个可视域
描述 本例展示了使用一个地理处理计算一个可视域(viewshed) 单击地图上的任意点查看该点5英里内能看见的所有区域.这个模型需要几秒钟来运行并反馈结果. 可视域计算是通过ArcGIS Server ...
- 关于Github Pages
迁移Github Pages 我稍微有一点强迫症,实在是忍受不了整洁的界面有一些推广的广告.正所谓博客平台不重要,重要的是要有干货,CSDN首页满屏的广告也就忍受了,但是自己的文章的页面有广告看着实在 ...