在MVC.Net中,如果我们想做一个统一的错误处理的模块,有几个选择,一种是通过一个Base Controller来实现,另外一种就是在Global.asax中实现。这里介绍后一种方法。
首先打开Global.asax文件,然后添加如下代码:
1 /** 2 * 捕捉系统级错误 3 **/ 4 void Application_Error(object sender, EventArgs e) 5 { 6 // We clear the response 7 Response.Clear(); 8 9 // 获取错误类 10 Exception exc = Server.GetLastError(); 11 12 // 检查是否Ajax请求,如果是的话,需要返回JSon结果 13 if (IsAjaxRequest()) 14 { 15 Response.Write("JSon结果"); 16 } 17 else 18 { 19 // 单独显示404页面 20 if (is404Error(exc)) { 21 Response.Redirect("/ERROR/E404"); 22 } 23 else 24 { 25 #if DEBUG 26 // 仅在调试阶段显示错误信息页面 27 StringBuilder sb = new StringBuilder(); 28 sb.Append("<html>"); 29 sb.AppendFormat(@"<body onload='document.forms[""form""].submit()'>"); 30 sb.AppendFormat("<form name='form' action='{0}' method='post'>", "/ERROR/DevOnly"); 31 sb.AppendFormat("<input type='hidden' name='message' value='{0}'>", 32 HttpUtility.UrlEncode(exc.Message)); // 此处必须Encode,否则单引号无法正确显示 33 sb.AppendFormat("<input type='hidden' name='source' value='{0}'>", 34 HttpUtility.UrlEncode(exc.Source)); // 此处必须Encode,否则单引号无法正确显示 35 sb.AppendFormat("<input type='hidden' name='stackTrace' value='{0}'>", 36 HttpUtility.UrlEncode(exc.StackTrace)); // 此处必须Encode,否则单引号无法正确显示 37 sb.AppendFormat("<input type='hidden' name='innerException' value='{0}'>", 38 HttpUtility.UrlEncode(exc.InnerException != null ? exc.InnerException.Message : "")); // 此处必须Encode,否则单引号无法正确显示 39 40 sb.Append("</form>"); 41 sb.Append("</body>"); 42 sb.Append("</html>"); 43 44 Response.Write(sb.ToString()); 45 46 Response.End(); 47 #else 48 Response.Redirect("/ERROR/"); 49 #endif 50 } 51 } 52 53 //We clear the error 54 Server.ClearError(); 55 } 56 57 /// <summary> 58 /// 检查是否属于404错误 59 /// </summary> 60 /// <param name="exc"></param> 61 /// <returns></returns> 62 private bool is404Error(Exception exc) 63 { 64 // Handle HTTP errors 65 if (exc.GetType() == typeof(HttpException)) 66 { 67 var httpException = (HttpException)exc; 68 if (httpException.GetHttpCode() == 404) 69 return true; 70 } 71 72 return false; 73 } 74 75 76 /// <summary> 77 /// 检查是否是Ajax请求 78 /// </summary> 79 /// <returns></returns> 80 private bool IsAjaxRequest() 81 { 82 //The easy way 83 bool isAjaxRequest = (Request["X-Requested-With"] == "XMLHttpRequest") 84 || ((Request.Headers != null) 85 && (Request.Headers["X-Requested-With"] == "XMLHttpRequest")); 86 87 //If we are not sure that we have an AJAX request or that we have to return JSON 88 //we fall back to Reflection 89 if (!isAjaxRequest) 90 { 91 try 92 { 93 //The controller and action 94 string controllerName = Request.RequestContext. 95 RouteData.Values["controller"].ToString(); 96 string actionName = Request.RequestContext. 97 RouteData.Values["action"].ToString(); 98 99 //We create a controller instance 100 DefaultControllerFactory controllerFactory = new DefaultControllerFactory(); 101 Controller controller = controllerFactory.CreateController( 102 Request.RequestContext, controllerName) as Controller; 103 104 //We get the controller actions 105 ReflectedControllerDescriptor controllerDescriptor = 106 new ReflectedControllerDescriptor(controller.GetType()); 107 ActionDescriptor[] controllerActions = 108 controllerDescriptor.GetCanonicalActions(); 109 110 //We search for our action 111 foreach (ReflectedActionDescriptor actionDescriptor in controllerActions) 112 { 113 if (actionDescriptor.ActionName.ToUpper().Equals(actionName.ToUpper())) 114 { 115 //If the action returns JsonResult then we have an AJAX request 116 if (actionDescriptor.MethodInfo.ReturnType 117 .Equals(typeof(JsonResult))) 118 return true; 119 } 120 } 121 } 122 catch 123 { 124 125 } 126 } 127 128 return isAjaxRequest; 129 }
在显示错误页面的地方,使用了将Reponse Redirect从Get变为Post的技巧,可以参考以前的文章。