我們平常在程序里面為了捕獲異常,會加上try-catch-finally代碼,但是這樣會使得程序代碼看起來很龐大,在MVC中我們可以使用異常過濾器來捕獲程序中的異常,如下圖所示:
使用了異常過濾器以后,我們就不需要在Action方法里面寫Try -Catch-Finally這樣的異常處理代碼了,而把這份工作交給HandleError去做,這個特性同樣可以應用到Controller上面,也可以應用到Action方面上面。
注意:
使用異常過濾器的時候,customErrors配置節屬性mode的值,必須為On。
演示示例:
1、Error控制器代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Data.SqlClient; 7 using System.IO; 8 9 namespace _3_異常過濾器.Controllers 10 { 11 public class ErrorController : Controller 12 { 13 // GET: Error 14 [HandleError(ExceptionType =typeof(ArithmeticException),View ="Error")] 15 public ActionResult Index(int a,int b) 16 { 17 int c = a / b; 18 ViewData["Result"] = c; 19 return View(); 20 } 21 22 /// <summary> 23 /// 測試數據庫異常 24 /// </summary> 25 /// <returns></returns> 26 [HandleError(ExceptionType = typeof(SqlException), View = "Error")] 27 public ActionResult DbError() 28 { 29 // 錯誤的連接字符串 30 SqlConnection conn = new SqlConnection(@"Initial Catalog=StudentSystem; Integrated Security=False;User Id=sa;Password=******;Data Source=127.0.0.1"); 31 conn.Open(); 32 // 返回Index視圖 33 return View("Index"); 34 } 35 36 /// <summary> 37 /// IO異常 38 /// </summary> 39 /// <returns></returns> 40 [HandleError(ExceptionType = typeof(IOException), View = "Error")] 41 public ActionResult IOError() 42 { 43 // 訪問一個不存在的文件 44 System.IO.File.Open(@"D:\error.txt",System.IO.FileMode.Open); 45 // 返回Index視圖 46 return View("Index"); 47 } 48 } 49 }
2、路由配置如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Web.Routing; 7 8 namespace _3_異常過濾器 9 { 10 public class RouteConfig 11 { 12 public static void RegisterRoutes(RouteCollection routes) 13 { 14 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 16 routes.MapRoute( 17 name: "Default", 18 url: "{controller}/{action}/{id}", 19 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 ); 21 22 // 新增路由配置 23 routes.MapRoute( 24 name: "Default2", 25 url: "{controller}/{action}/{a}/{b}", 26 defaults: new { controller = "Home", action = "Index", a=0,b=0 } 27 ); 28 } 29 } 30 }
3、配置文件如下:
<system.web> <compilation debug="true" targetFramework="4.6.1" /> <httpRuntime targetFramework="4.6.1" /> <httpModules> <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" /> </httpModules> <!--customErrors配置節mode的屬性值必須為On--> <customErrors mode="On"> </customErrors> </system.web>
4、運行結果
URL:http://localhost:21868/error/index/8/4
結果:
URL:http://localhost:21868/error/index/8/0
結果:
URL:http://localhost:21868/error/DbError
結果:
URL:http://localhost:21868/error/IOError
結果:
在同一個控制器或Action方法上可以通過HandleError處理多個異常,通過Order屬性決定捕獲的先后順序,但最上面的異常必須是下面異常的同類級別或子類。如下圖所示:
上面的程序可以修改成如下的代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Data.SqlClient; 7 using System.IO; 8 9 namespace _3_異常過濾器.Controllers 10 { 11 [HandleError(Order =1, ExceptionType = typeof(SqlException), View = "Error")] 12 [HandleError(Order =2, ExceptionType = typeof(IOException), View = "Error")] 13 [HandleError(Order =3)] //不指定View,默認跳轉到Share下面的Error視圖 14 public class ErrorController : Controller 15 { 16 public ActionResult Index(int a,int b) 17 { 18 int c = a / b; 19 ViewData["Result"] = c; 20 return View(); 21 } 22 23 /// <summary> 24 /// 測試數據庫異常 25 /// </summary> 26 /// <returns></returns> 27 public ActionResult DbError() 28 { 29 // 錯誤的連接字符串 30 SqlConnection conn = new SqlConnection(@"Initial Catalog=StudentSystem; Integrated Security=False;User Id=sa;Password=******;Data Source=127.0.0.1"); 31 conn.Open(); 32 // 返回Index視圖 33 return View("Index"); 34 } 35 36 /// <summary> 37 /// IO異常 38 /// </summary> 39 /// <returns></returns> 40 public ActionResult IOError() 41 { 42 // 訪問一個不存在的文件 43 System.IO.File.Open(@"D:\error.txt",System.IO.FileMode.Open); 44 // 返回Index視圖 45 return View("Index"); 46 } 47 } 48 }
在上面的示例中,捕獲異常的時候只是跳轉到了Error視圖,如果我們想獲取異常的具體信息該怎么辦呢?如下圖所示:
查看MVC源碼,可以發現HandleError返回的是HandleErrorInfo類型的model,利用該model可以獲取異常的具體信息,修改Error視圖頁面如下:
@model HandleErrorInfo <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta name="viewport" content="width=device-width" /> <title>錯誤</title> <style type="text/css"> p{ color:red; } </style> </head> <body> @*<hgroup> <h1>錯誤。</h1> <h2>處理你的請求時出錯。</h2> </hgroup>*@ <p> 拋錯控制器:<b>@Model.ControllerName</b> 拋錯方法:<b>@Model.ActionName</b> 拋錯類型:<b>@Model.Exception.GetType()</b> </p> <p> 異常信息:@Model.Exception.Message </p> <p> 堆棧信息:@Model.Exception.StackTrace </p> </body> </html>
結果: