ASP.NET MVC-異常處理&自定義錯誤頁

来源:https://www.cnblogs.com/chenxinblogs/archive/2018/04/20/8822197.html
-Advertisement-
Play Games

一、應用場景 對於B/S應用程式,在部署到正式環境運行的過程中,很有可能出現一些在前期測試過程中沒有發現的一些異常或者錯誤,或者說只有在特定條件滿足時才會發生的一些異常,對於使用ASP.NET MVC開發的應用程式站點,在部署到IIS上後,如果開發人員未對程式進行錯誤處理,那麼一旦程式出現未處理的錯 ...


一、應用場景

 對於B/S應用程式,在部署到正式環境運行的過程中,很有可能出現一些在前期測試過程中沒有發現的一些異常或者錯誤,或者說只有在特定條件滿足時才會發生的一些異常,對於使用ASP.NET MVC開發的應用程式站點,在部署到IIS上後,如果開發人員未對程式進行錯誤處理,那麼一旦程式出現未處理的錯誤或異常,用戶將看到一個讓人感到及其困惑的錯誤堆棧跟蹤頁面,使得站點的用戶體驗下降,從程式的角度上來說,不做自定義錯誤處理也不利於程式出問題時的根源查找,因為很多時候有些錯誤只在特定條件下滿足時才重現,一旦錯過,可能就需要花大量時間去測試來重現問題,如果此時開發人員有對程式中的運行時異常進行日誌記錄,那麼或許將提供一些有價值的錯誤根源信息,下麵我將向下大家講解如何實現自定義異常處理並跳轉到友好的錯誤提示頁面。

二、異常處理&自定義錯誤頁

1、通過異常過濾器 實現異常處理和自定義錯誤頁

  asp.net mvc 提供了 異常過濾器 的方式來實現當執行controller中某個action方法時拋出了未處理的異常時的捕捉,mvc中的異常過濾器是以特性(Attribute)的形式存在的,定義一個自定義異常過濾器只需要兩個步驟:

1、定義一個類,繼承FilterAttribute類,並實現IExceptionFilter介面 2、應用自定義異常過濾器至指定的 action方法 或 controller類 或 全局應用。

異常過濾器代碼

 1 using log4net;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace Blog20180413.Filters
 9 {
10     public class CustomExceptionFilterAttribute : FilterAttribute, IExceptionFilter
11     {
12         //log4net組件,用於日誌記錄。
13         static readonly ILog log = LogManager.GetLogger(typeof(CustomExceptionFilterAttribute));
14         public void OnException(ExceptionContext filterContext)
15         {
16             //對捕獲到的異常信息進行日誌記錄,方便開發人員排查問題。
17             log.Error("應用程式異常", filterContext.Exception);
18 
19             //跳轉到自定義的錯誤頁,增強用戶體驗。
20             ActionResult result = new ViewResult() { ViewName = "CustomErrorPage" };
21             filterContext.Result = result;
22             //異常處理結束後,一定要將ExceptionHandled設置為true,否則仍然會繼續拋出錯誤。
23             filterContext.ExceptionHandled = true;
24         }
25     }
26 }
View Code

使用異常過濾器

 1 using Blog20180413.Filters;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace Blog20180413.Controllers
 9 {
10     public class TestExceptionHandleController : Controller
11     {
12         [CustomExceptionFilter]
13         public ActionResult Index()
14         {
15             string str = string.Empty;
16             //將拋出轉換異常
17             int result = int.Parse(str);
18             return View();
19         }
20     }
21 }
View Code

註意:

第二個步驟中提到,可以將自定義異常過濾器 只應用到 action或者controller,如果只想將指定的異常過濾器以特性的形式應用到指定的一個或者多個controller或者action,而不想應用到所有的controller或者action,那麼必須將該異常過濾器繼承FilterAttribute類,這是因為mvc框架是通過FilterAttributeFilterProvider.GetFilters來獲取標記在指定controller或者action上的異常過濾器特性的,而GetFilters內部邏輯要求必須繼承自FilterAttribute類。

如果需要將自定義的異常過濾器應用到所有的controller的action上,那麼需要將該自定義異常過濾器註冊到全局,代碼如下:

 1 using Blog20180413.Filters;
 2 using System.Web;
 3 using System.Web.Mvc;
 4 
 5 namespace Blog20180413
 6 {
 7     public class FilterConfig
 8     {
 9         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
10         {
11             filters.Add(new CustomExceptionFilterAttribute());
12         }
13     }
14 }

 

2、通過在Global.asax 中定義Application_Error方法 實現異常處理和自定義錯誤頁

上面提到的 自定義異常過濾器只能捕獲在執行action方法過程中拋出的異常(即使註冊為全局過濾器也只能捕獲action方法執行過程中拋出的異常),如果需要捕獲更高級別的異常,也就是在請求執行過程中出現的任何異常(如在控制器的構造函數中拋出異常),那麼可以使用該種方式,代碼如下:

 

 1 using log4net;
 2 using log4net.Config;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.IO;
 6 using System.Linq;
 7 using System.Web;
 8 using System.Web.Mvc;
 9 using System.Web.Routing;
10 
11 namespace Blog20180413
12 {
13     public class MvcApplication : System.Web.HttpApplication
14     {
15         static readonly ILog log = LogManager.GetLogger(typeof(MvcApplication));
16         protected void Application_Start()
17         {
18             AreaRegistration.RegisterAllAreas();
19             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
20             RouteConfig.RegisterRoutes(RouteTable.Routes);
21             XmlConfigurator.ConfigureAndWatch(new FileInfo(Server.MapPath("~/web.config")));
22         }
23 
24         protected void Application_Error(object sender, EventArgs e)
25         {
26             Exception exception = Server.GetLastError();
27             //Server.ClearError();
28             //這裡記錄錯誤日誌信息
29             log.Error("MvcApplication 捕獲異常", exception);
30             //跳轉到指定的自定義錯誤頁
31             Response.Redirect("/CustomErrorHandle/CustomErrorPage");
32         }
33     }
34 }
View Code

 

 

3、通過配置system.web->customErrors節點 實現自定義錯誤頁

  當你的站點發生異常時,如果你只是想簡單的跳轉到一個自定義錯誤頁面,而不是對異常進一步處理時,那麼你可以簡單的作如下配置操作即可:

需要在web.config中做如下配置:

 

1 <system.web>
2     <customErrors mode="On" defaultRedirect="CustomErrorPage">
3     </customErrors>
4 </system.web>

 

註意:這裡的CustomErrorPage是一個視圖文件,放在Shared共用目錄下。

如果你註冊了HandleErrorAttribute異常過濾器到全局,那麼在你的錯誤頁中將能獲取到和異常相關的一些信息。但此時配置到defaultRedirect的值的必須是Error

也就是自定義錯誤視圖頁面的名稱必須為Error.cshtml,並且放在Shared目錄,當然,你也可以通過在創建HandleErrorAttribute全局過濾器的過程中,設置器View屬性,這樣你就可以不用講錯誤視圖的名稱設置為Error了.如下:

1 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
2 {
3             HandleErrorAttribute errorAttribute = new HandleErrorAttribute();
4             errorAttribute.View = "CustomErrorPage";
5             filters.Add(errorAttribute);
6 }

 

註冊HandleErrorAttribute(使用預設的錯誤視圖頁面文件名)

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }

定義Error.cshtml視圖頁

 1 @{
 2     Layout = null;
 3 }
 4 @model HandleErrorInfo
 5 <!DOCTYPE html>
 6 <html>
 7 <head>
 8     <meta name="viewport" content="width=device-width" />
 9     <title>Error</title>
10 </head>
11 <body>
12     <div>
13         @*通過HandleErrorAttribute異常過濾器捕獲到的異常信息存儲在Model屬性中*@
14         @Model.Exception.Message
15     </div>
16 </body>
17 </html>
View Code

 之所以通過註冊HandleErrorAttribute過濾器捕獲的異常在錯誤頁中能獲取異常信息可以看HandleErrorAttribute類的內部實現,發現載入錯誤視圖頁面的過程中,傳遞了一個HandleErrorInfo對象過去。

 1 public virtual void OnException(ExceptionContext filterContext)
 2 {
 3     if (filterContext == null)
 4     {
 5         throw new ArgumentNullException("filterContext");
 6     }
 7     if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
 8     {
 9         Exception innerException = filterContext.Exception;
10         if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))
11         {
12             string controllerName = (string) filterContext.RouteData.Values["controller"];
13             string actionName = (string) filterContext.RouteData.Values["action"];
14             HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
15             ViewResult result = new ViewResult {
16                 ViewName = this.View,
17                 MasterName = this.Master,
18                 ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
19                 TempData = filterContext.Controller.TempData
20             };
21             filterContext.Result = result;
22             filterContext.ExceptionHandled = true;
23             filterContext.HttpContext.Response.Clear();
24             filterContext.HttpContext.Response.StatusCode = 500;
25             filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
26         }
27     }
28 }
View Code
 1 public string View
 2 {
 3     get
 4     {
 5         if (string.IsNullOrEmpty(this._view))
 6         {
 7             return "Error";
 8         }
 9         return this._view;
10     }
11     set => 
12         (this._view = value);
13 }
14  
View Code

 

 

三、總結

 總的來說,Application_Error方法用於處理針對請求管道級別的發生的異常錯誤,而Mvc異常過濾器則只能處理在執行action方法過程中出現的異常.能處理的範圍相對Application_Error較小,但在實際項目開發中,用Mvc異常過濾器處理異常相對會多一點,因為我們的功能業務往往體現在控制器的action方法執行的過程中,也就是在這個過程中較容易產生異常。故開發中用Mvc異常過濾器就能適應大部分的異常處理需求。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在做MVC站點時(使用IIS版本為7.5),使用Get請求,當Url里查詢字元串過長時,會出現如下錯誤: 出現該錯誤的原因為:IIS7.5對於Query String有長度限制,預設為2048。 按照圖中可嘗試的操作提示,可以通過如下兩種方法來解決問題 1.在MVC站點的web.config里,<s ...
  • 方法1:響應Ctrl+?快捷鍵 首先在load事件或者keydown事件內註冊事件 註冊的事件如下(檢測Ctrl+V和Ctrl+N): 方法2:響應Ctrl+滑鼠滾輪 說明:所有UI元素都具有PointerWheelChanged事件,響應此事件同時判斷Ctrl狀態判斷用戶操作。例子中響應的UIEl ...
  • .netcore中的數據配置及內容用了json文件代替了之前framework的xml文件,那麼json中的數據該怎麼獲取呢?下麵講解json文件在.net core中的獲取方法. 首先,新建一個.net core web應用程式,然後新建文件夾JsonFile,併在JsonFile文件夾中新建cl ...
  • 感謝兩位兩位大佬: https://blog.csdn.net/l1028386804/article/details/61417166 https://www.cnblogs.com/runningsmallguo/p/6239215.html 1.首先我們要下載好文件memcached.exe, ...
  • 前言:先到微軟的 https://www.iis.net/downloads/microsoft/url-rewrite 下載URL Rewrite 前言:先到微軟的 https://www.iis.net/downloads/microsoft/url-rewrite 下載URL Rewrite ...
  • using System; using System.Security.Cryptography; using System.Text; namespace DimoNetwork.Common.DEncrypt { public enum MD5ResultMode : byte { Strong... ...
  • 我採用asp.net進行演示 送給有緣人吧,可以獲得類似版本號的功能,也可以對比兩個版本號,我這裡是其他需要用逗號分割的 ...
  • 1.首先新建一個winform的項目。 2.確保C#工具箱包含ESRI的相關控制項,如果沒有就需要安裝SDK。 如果VS中依舊不存在esri控制項解決方案如下,以VS2013為例: (1)打開註冊表,定位至HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...