ASP.NET MVC 異常處理之最佳實現(xiàn)

點擊查看原文

異常處理是所有應(yīng)用程序的的一個重要部分。ASP.NET 為處理異常提供了數(shù)種不同的方法配名。在這篇文章中,我們將學(xué)習(xí)如何最佳的實現(xiàn) ASP.NET MVC 異常處理。

MVC異常處理的5種方法

在 .NET 鲁沥、ASP.NET 和 MVC 之間有幾種可行的方式來處理應(yīng)用程序異常荠锭。

  • Web.Config 文件中的 <customErrors> 結(jié)點
  • MVC 的 HandleError 特性
  • Controller.OnException 方法
  • HttpApplication Application_Error 事件
  • 使用Stackify 的 Retrace 收集異常

這些異常處理方法都有各自的優(yōu)缺點旱眯。您可能需要組合使用它們才能正確處理異常并記錄錯誤信息。
在異常處理時证九,你需要完成兩個重要的事情:

  1. 優(yōu)雅地處理異常并向用戶展示友好的錯誤頁面删豺。
  2. 記錄錯誤方便您了解并監(jiān)控錯誤信息。

必須項:在 Web.Config 的 <customErrors> 結(jié)點中配置全局錯誤頁面

向您的用戶展示“yellow screen of death(黃色錯誤頁)”是您的最后一個選擇愧怜。如果您不知道那是什么的話呀页,那正是我所談?wù)摰臉?biāo)準(zhǔn)的黃色ASP.NET錯誤頁面。

對于所有應(yīng)用程序拥坛,我總是建議在您的 Web.Config 中指定自定義錯誤頁面蓬蝶。最壞情景下,如果出現(xiàn)未處理的異常猜惋,用戶看到的也將是配置中指定的自定義錯誤頁面丸氛。

<system.web>
    <customErrors mode="On" defaultRedirect="~/ErrorHandler/Index">
        <error statusCode="404" redirect="~/ErrorHandler/NotFound"/>
    </customErrors>
<system.web/>

更多信息:How to Use Web.Config customErrors for ASP.NET

使用 MVC HandleErrorAttribute 自定義 Responses

HandleErrorAttribute 繼承自 FilterAttribute ,可以應(yīng)用于整個 controller 或著 controller 中某個的 action 方法著摔。

---------------
/*
* HandleErrorAttribute 定義如下:
*/
 public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    //Other members...

    /// <summary>Called when an exception occurs.</summary>
    /// <param name="filterContext">The action-filter context.</param>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="filterContext" /> parameter is null.</exception>
    public virtual void OnException(ExceptionContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");
        if (filterContext.IsChildAction || filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            return;
        Exception exception = filterContext.Exception;
        //500
        if (new HttpException((string)null, exception).GetHttpCode() != 500 || !this.ExceptionType.IsInstanceOfType((object)exception))
            return;
        string controllerName = (string)filterContext.RouteData.Values["controller"];
        string actionName = (string)filterContext.RouteData.Values["action"];
        HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        ExceptionContext exceptionContext = filterContext;
        ViewResult viewResult1 = new ViewResult();
        viewResult1.ViewName = this.View;
        viewResult1.MasterName = this.Master;
        viewResult1.ViewData = (ViewDataDictionary)new ViewDataDictionary<HandleErrorInfo>(model);
        viewResult1.TempData = filterContext.Controller.TempData;
        ViewResult viewResult2 = viewResult1;
        exceptionContext.Result = (ActionResult)viewResult2;
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 500;
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

HandleErrorAttribute 只能處理在MVC action方法中發(fā)生的 Http Status Code 等于 500(Internal Server Error)的錯誤雪位。它不會追蹤在MVC管道之外幫助的異常。在其他HTTP模塊梨撞、MVC路由等可能出現(xiàn)異常雹洗。

什么時候該使用 HandleErrorAttribute ?

由于它無法捕獲所有的可能出現(xiàn)異常卧波,所以對于全局未處理的異常處理來說這是一個糟糕的解決方案时肿。

它適用于為特定的 MVC controller 或 action 方法指定特定的錯誤頁面。在您的 Web.Config 的 <customErrors> 結(jié)點中港粱,指定一個錯誤頁面適用于通用(全局)錯誤頁面螃成。HandleErrorAttribute 可以給你更精細(xì)的控制,如果您需要的話查坪。

注意:如果您需要使用 HandleErrorAttribute寸宏,請確保在您的Web.Config 中 <customErrors> 結(jié)點設(shè)為 On。

舉個例子偿曙,當(dāng)出現(xiàn) SqlException 異常時氮凝,你希望顯示一個特定的頁面,你可以使用類似于如下的代碼:

[HandleError(ExceptionType = typeof(SqlException), View = "SqlExceptionView")]
public string GetClientInfo(string username)
{
    return Dll.Query(username);
}

使用 HandleErrorAttribute 的缺點是望忆,它無法記錄異常日志罩阵!

使用 MVC Controller OnException 來自定義 Responses

OnException 方法與 HandleErrorAttribute 相似竿秆,但是更為靈活。它可以處理所有的 Http Status Code稿壁,而不僅僅是 Http Status Code 等于 500 的錯誤幽钢。同樣你也可以記錄異常日志。

/*
* IExceptionFilter 接口 的 OnException 方法定義如下:
*/
namespace System.Web.Mvc
{
  /// <summary>Defines the methods that are required for an exception filter.</summary>
  public interface IExceptionFilter
  {
    /// <summary>Called when an exception occurs.</summary>
    /// <param name="filterContext">The filter context.</param>
    void OnException(ExceptionContext filterContext);
  }
}

示例:

public class UserMvcController : Controller
{
   protected override void OnException(ExceptionContext filterContext)
   {
      filterContext.ExceptionHandled = true;

      //Log the error!!
      _Logger.Error(filterContext.Exception);

      //Redirect or return a view, but not both.
      filterContext.Result = RedirectToAction("Index", "ErrorHandler");
      // OR 
      filterContext.Result = new ViewResult
      {
         ViewName = "~/Views/ErrorHandler/Index.cshtml"
      };
   }
}

什么時候使用 OnException 方法處理 MVC 異常傅是?

如果您希望為用戶展示自定義的錯誤頁面匪燕,或者記錄自定義異常信息,那 OnException 就是一個很棒的解決方案喧笔。 相比 HandleErrorAttribute 它更為靈活谎懦,而且不需要將 Web.Config 中的 <customErrors> 設(shè)置為 On。

注意: 所有 HTTP status codes 都會調(diào)用 OnException 方法溃斋。所以對于簡單錯誤(如:由于錯誤的Url引發(fā)的404錯誤)的處理需要你十分小心界拦。

使用 HttpApplication Application_Error 作為全局異常處理

到目前為止,我們已經(jīng)介紹了三種不同的方法來自定義異常發(fā)生時您的用戶將看到的響應(yīng)梗劫,OnException 是你唯一可以用來記錄異常信息的選項享甸。

為了記錄應(yīng)用程序中可能發(fā)生的所有未處理的異常,你應(yīng)該實現(xiàn)基本錯誤的日志記錄功能梳侨,如下所示:

public class MvcApplication : System.Web.HttpApplication
{
   protected void Application_Start()
   {
      AreaRegistration.RegisterAllAreas();
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);
   }

   protected void Application_Error()
   {
      var ex = Server.GetLastError();
      //log the error!
      _Logger.Error(ex);
   }
}

什么時候使用 Application_Error 蛉威?

Always!HttpApplication 的 Application_Error 方法提供了收集和記錄所有未處理的錯誤的最佳機(jī)制走哺。

用Stackify Retrace收集所有.NET異常

Stackify的APM解決方案Retrace輕松訪問.NET性能分析API蚯嫌,以跟蹤應(yīng)用程序的性能,直至代碼級別丙躏。 作為它的一部分择示,它可以自動收集所有未處理的異常,或被配置為接收所有拋出的異常晒旅,即使它們被處理和丟棄栅盲。 Retrace不需要任何代碼更改!

Retrace允許您查看和監(jiān)視所有的應(yīng)用程序錯誤废恋。 查看我們的錯誤監(jiān)控功能以了解更多信息谈秫。


Retrace

總結(jié)

有多種方法可以完成 MVC 錯誤處理。您總是應(yīng)該在 Web.Config中的 <customErrors>結(jié)點中指定默認(rèn)的錯誤頁面鱼鼓,并且在 HttpApplication 的 Application_Error 方法中記錄未處理的異常信息拟烫。

HandleErrorAttribute 或者 OnException 為用戶顯示錯誤方式提供更為精細(xì)的控制。

如果你想跟蹤所有的應(yīng)用程序異常迄本,請確保檢查我們的Retrace和我們的錯誤監(jiān)控功能硕淑。 您還可以使用我們的免費探查器Prefix,免費查看您的工作站上的所有應(yīng)用程序異常。

更多信息:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喜颁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子曹阔,更是在濱河造成了極大的恐慌半开,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赃份,死亡現(xiàn)場離奇詭異寂拆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抓韩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門纠永,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谒拴,你說我怎么就攤上這事尝江。” “怎么了英上?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵炭序,是天一觀的道長。 經(jīng)常有香客問我苍日,道長惭聂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任相恃,我火速辦了婚禮辜纲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拦耐。我一直安慰自己耕腾,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布杀糯。 她就那樣靜靜地躺著幽邓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪火脉。 梳的紋絲不亂的頭發(fā)上牵舵,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音倦挂,去河邊找鬼畸颅。 笑死,一個胖子當(dāng)著我的面吹牛方援,可吹牛的內(nèi)容都是我干的没炒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼犯戏,長吁一口氣:“原來是場噩夢啊……” “哼送火!你這毒婦竟也來了拳话?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤种吸,失蹤者是張志新(化名)和其女友劉穎弃衍,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坚俗,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡镜盯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了猖败。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片速缆。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖恩闻,靈堂內(nèi)的尸體忽然破棺而出艺糜,到底是詐尸還是另有隱情,我是刑警寧澤幢尚,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布倦踢,位于F島的核電站,受9級特大地震影響侠草,放射性物質(zhì)發(fā)生泄漏辱挥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一边涕、第九天 我趴在偏房一處隱蔽的房頂上張望晤碘。 院中可真熱鬧,春花似錦功蜓、人聲如沸园爷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽童社。三九已至,卻和暖如春著隆,著一層夾襖步出監(jiān)牢的瞬間扰楼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工美浦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留弦赖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓浦辨,卻偏偏與公主長得像蹬竖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354