MVC全局异常处理
眾所周知,在asp.net世界中,對于異常的處理就是try catch,當然這個是在方法內部,還有Page_Error 頁面級別的錯誤,application_error 應用程序級別的錯誤,這幾個地方可以用來處理異常信息。一般情況下,我們對于已知的可能出現的錯誤會直接在try catch中捕獲并且處理,但是對于那些我們沒有考慮到的異常信息,我們就要采取別的辦法了,比如定義一個基類,用來處理子類拋出的異常,然后在可能出現 異常信息的地方繼承該類,讓父類處理子類中不能確定的并且是拋出的未處理的異常信息。這個和驗證用戶是否登陸的方式基本一樣,對于某些資源,需要有權限的 用戶才能訪問,我們就會定義一個基類,用來驗證用戶是否登陸,如果登陸才可以繼續執行,否則就要跳轉到登陸界面。
當然,前面說的處理 異常的方式是在web form時代我們(起碼是我)常用的方式,但是在MVC 時代到臨的時候,這些處理是否更容易呢?答案是肯定的,因為技術是在不斷進步的嘛。在MVC中我們對于已知的異常信息仍然會采用try catch的方式,并且是很常用的方式,但是對于驗證用戶登陸或者catch未捕獲的異常信息(當然我的意思是catch(exception ex) 在catch最后沒有這一條,或者說有這一句,但是把異常信息進行了拋出處理),我們有了更容易實現的方式。下面讓我們一起走進如何使用MVC處理異常信 息。在軟件架構不斷發展的同時,設計模式也有了很多變種,AOP(面向切面編程或面向方面編程)就是一個變種的設計模式,對于設計模式的學習,我個人不推 薦死記硬背,我希望可以了解每種模式的意義,然后在項目中不要刻意的去使用它,而是在重構的時候進行,這樣我們可以更加深入的了解設計模式背后包含的含 義。舉個例子,單例模式是一個經典的設計模式,它可以保證類的實例只有一個,但是如果我們不正確的使用這種方式,有時候會帶來負面效果,比如多線程同時訪 問,只有在保證加鎖、解鎖的情況下可以保證,[url=http://www.hengtaitraining.com/net/]北京.NET培訓 [/url]但是在普通情況下就會出現意想不到的錯誤信息。面向對象編程具有繼承性,這應該是面向對象三大特性之一,這是類的垂直方面的編程工作,有上下 級或父子關系,AOP是水平方面的編程,它可以保證在開始之前或結束之后進行,不會破壞里面的結構。個人粗淺理解。在MVC 3中對AOP的支持就表現在filter 過濾器上,他可以保證在開始之前或結束之后進行。對于異常的處理我們采用的是自定義異常處理信息繼承自IExceptionFilter,當然在MVC總 內置了一個HandleErrorAttribute也可以用來捕獲異常,但是我們自己來控制可能會更好一些。
首先我們在HomeController的Index方法中拋出一個異常信息
1 public ActionResult Index(int? id, int pageSize = 20)
2 {
3 List blogList = BlogServices.GetAllBlogList().ToPagedList(id == null ? 1 : Convert.ToInt32(id), pageSize);
4 ViewBag.BlogList = blogList;
5 if (Request.IsAjaxRequest())
6 {
7
8 }
9
10 throw new HttpException(500, "");//拋出異常信息
11
12
13 return View(blogList);
14 }
15 //404Not Found
16 public ActionResult NotFound()
17 {
18 return View();
19 }
20 //內部服務器錯誤 500
21 public ActionResult InternalError()
22 {
23 return View();
24 }
2.設置自定義處理異常類
1 public class CustomExceptionAttribute :FilterAttribute,IExceptionFilter //HandleErrorAttribute
2 {
3
4 public void OnException(ExceptionContext filterContext)
5 {
6 if (filterContext.ExceptionHandled == true)
7 {
8 HttpException httpExce = filterContext.Exception as HttpException;
9 if (httpExce.GetHttpCode() != 500)//為什么要特別[url=http://www.hengtaitraining.com/net/]北京.NET培訓[/url]強調500 因為MVC處理HttpException的時候,如果為500 則會自動
10 //將其ExceptionHandled設置為true,那么我們就無法捕獲異常
11 {
12 return;
13 }
14 }
15 HttpException httpException = filterContext.Exception as HttpException;
16 if (httpException != null)
17 {
18 filterContext.Controller.ViewBag.UrlRefer = filterContext.HttpContext.Request.UrlReferrer;
19 if (httpException.GetHttpCode() == 404)
20 {
21 filterContext.HttpContext.Response.Redirect("~/home/notfound");
22 }
23 else if (httpException.GetHttpCode() == 500)
24 {
25 filterContext.HttpContext.Response.Redirect("~/home/internalError");
26 }
27 }
28 //寫入日志 記錄
29 filterContext.ExceptionHandled = true;//設置異常已經處理
30 }
31 }
在這里我要多說一句,有些園友可能遇到這么一個問題,就是拋出了一個500的內部服務器異常,但是在自定義異常信息中就是無法捕獲到,是什么原因呢?
其實就是MVC對500 的特殊照顧,在HttpException的httpCode為500的時候,MVC框架會自動的處理,然后將其ExceptionHandled設置為true。
對于其他的異常狀態碼,比如404就沒有這樣的照顧,所以500我們要優先照顧呀。
3.在設置好了自定義異常處理以后,我們可以在每個Action或Controller中進行注入,但是在MVC 3 中提供了另外一種可以全局注入的方式,[url=http://www.hengtaitraining.com/net/]北京.NET培訓 [/url]那就是全局Filter,我一般叫做全局篩選器。這樣就相當于我們在所有的Action上都進行了注入。
在global.asax中,進行全局注冊
1 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
2 {
3 filters.Add(new CustomExceptionAttribute(),1);//自定義的驗證特性
4 filters.Add(new HandleErrorAttribute(),2);
5 }
4.我們在設置了自定義異常處理以后,會跳轉到對應的頁面,里面的信息相信大家都可以自己定制了
5.有圖有證據 先來一個404異常處理信息
我請求的頁面是home/index,然后自動跳轉到了notFound頁面
還有500錯誤,如果您不注意判斷一個這個錯誤,那么你是不可能的
總結一下,在MVC中處理異常有很多中方式,HandleErrorAttribute,自定義異常處理類(重寫IExceptionFilter或者 是HandleErrorAttribute 的OnException方法),傳統的try catch方法,這些都可以,除去那個try catch,其實自定義異常處理就是Filter的體現,和登陸驗證沒有任何區別。
還有一點就是HttpException的HttpCode為500的情況,ExceptionHandled會被自動設置為true,需要特殊照顧一下。
在我們處理完了異常以后,一定要將其ExceptionHandled設置為true,這樣可以避免父類或者更高一級的異常處理捕獲處理該異常信息。
MVC處理異常就是這么簡單,Filter特性就是那么強大,讓我們擁抱MVC,擁抱filter。
轉載于:https://www.cnblogs.com/tanzhen/p/4820061.html
總結
- 上一篇: 第十一章:集合(一)
- 下一篇: ListView单选的实现总结(转)