異常處理是所有應(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)缺點旱眯。您可能需要組合使用它們才能正確處理異常并記錄錯誤信息。
在異常處理時证九,你需要完成兩個重要的事情:
- 優(yōu)雅地處理異常并向用戶展示友好的錯誤頁面删豺。
- 記錄錯誤方便您了解并監(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)控功能以了解更多信息谈秫。
總結(jié)
有多種方法可以完成 MVC 錯誤處理。您總是應(yīng)該在 Web.Config中的 <customErrors>結(jié)點中指定默認(rèn)的錯誤頁面鱼鼓,并且在 HttpApplication 的 Application_Error 方法中記錄未處理的異常信息拟烫。
HandleErrorAttribute 或者 OnException 為用戶顯示錯誤方式提供更為精細(xì)的控制。
如果你想跟蹤所有的應(yīng)用程序異常迄本,請確保檢查我們的Retrace和我們的錯誤監(jiān)控功能硕淑。 您還可以使用我們的免費探查器Prefix,免費查看您的工作站上的所有應(yīng)用程序異常。