ASP.NET MVC中異常處理&自定義錯(cuò)誤頁詳析
一、應(yīng)用場(chǎng)景
對(duì)于B/S應(yīng)用程序,在部署到正式環(huán)境運(yùn)行的過程中,很有可能出現(xiàn)一些在前期測(cè)試過程中沒有發(fā)現(xiàn)的一些異?;蛘咤e(cuò)誤,或者說只有在特定條件滿足時(shí)才會(huì)發(fā)生的一些異常,對(duì)于使用ASP.NET MVC開發(fā)的應(yīng)用程序站點(diǎn),在部署到IIS上后,如果開發(fā)人員未對(duì)程序進(jìn)行錯(cuò)誤處理,那么一旦程序出現(xiàn)未處理的錯(cuò)誤或異常,用戶將看到一個(gè)讓人感到及其困惑的錯(cuò)誤堆棧跟蹤頁面,使得站點(diǎn)的用戶體驗(yàn)下降,從程序的角度上來說,不做自定義錯(cuò)誤處理也不利于程序出問題時(shí)的根源查找,因?yàn)楹芏鄷r(shí)候有些錯(cuò)誤只在特定條件下滿足時(shí)才重現(xiàn),一旦錯(cuò)過,可能就需要花大量時(shí)間去測(cè)試來重現(xiàn)問題,如果此時(shí)開發(fā)人員有對(duì)程序中的運(yùn)行時(shí)異常進(jìn)行日志記錄,那么或許將提供一些有價(jià)值的錯(cuò)誤根源信息,下面我將向下大家講解如何實(shí)現(xiàn)自定義異常處理并跳轉(zhuǎn)到友好的錯(cuò)誤提示頁面。
二、異常處理&自定義錯(cuò)誤頁
1、通過異常過濾器 實(shí)現(xiàn)異常處理和自定義錯(cuò)誤頁
asp.net mvc 提供了 異常過濾器 的方式來實(shí)現(xiàn)當(dāng)執(zhí)行controller中某個(gè)action方法時(shí)拋出了未處理的異常時(shí)的捕捉,mvc中的異常過濾器是以特性(Attribute)的形式存在的,定義一個(gè)自定義異常過濾器只需要兩個(gè)步驟:
1、定義一個(gè)類,繼承FilterAttribute類,并實(shí)現(xiàn)IExceptionFilter接口 2、應(yīng)用自定義異常過濾器至指定的 action方法 或 controller類 或 全局應(yīng)用。
異常過濾器代碼
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Blog20180413.Filters
{
public class CustomExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
//log4net組件,用于日志記錄。
static readonly ILog log = LogManager.GetLogger(typeof(CustomExceptionFilterAttribute));
public void OnException(ExceptionContext filterContext)
{
//對(duì)捕獲到的異常信息進(jìn)行日志記錄,方便開發(fā)人員排查問題。
log.Error("應(yīng)用程序異常", filterContext.Exception);
//跳轉(zhuǎn)到自定義的錯(cuò)誤頁,增強(qiáng)用戶體驗(yàn)。
ActionResult result = new ViewResult() { ViewName = "CustomErrorPage" };
filterContext.Result = result;
//異常處理結(jié)束后,一定要將ExceptionHandled設(shè)置為true,否則仍然會(huì)繼續(xù)拋出錯(cuò)誤。
filterContext.ExceptionHandled = true;
}
}
}
使用異常過濾器
using Blog20180413.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Blog20180413.Controllers
{
public class TestExceptionHandleController : Controller
{
[CustomExceptionFilter]
public ActionResult Index()
{
string str = string.Empty;
//將拋出轉(zhuǎn)換異常
int result = int.Parse(str);
return View();
}
}
}
注意:
第二個(gè)步驟中提到,可以將自定義異常過濾器 只應(yīng)用到 action或者controller,如果只想將指定的異常過濾器以特性的形式應(yīng)用到指定的一個(gè)或者多個(gè)controller或者action,而不想應(yīng)用到所有的controller或者action,那么必須將該異常過濾器繼承FilterAttribute類,這是因?yàn)閙vc框架是通過FilterAttributeFilterProvider.GetFilters來獲取標(biāo)記在指定controller或者action上的異常過濾器特性的,而GetFilters內(nèi)部邏輯要求必須繼承自FilterAttribute類。
如果需要將自定義的異常過濾器應(yīng)用到所有的controller的action上,那么需要將該自定義異常過濾器注冊(cè)到全局,代碼如下:
using Blog20180413.Filters;
using System.Web;
using System.Web.Mvc;
namespace Blog20180413
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomExceptionFilterAttribute());
}
}
}
2、通過在Global.asax 中定義Application_Error方法 實(shí)現(xiàn)異常處理和自定義錯(cuò)誤頁
上面提到的 自定義異常過濾器只能捕獲在執(zhí)行action方法過程中拋出的異常(即使注冊(cè)為全局過濾器也只能捕獲action方法執(zhí)行過程中拋出的異常),如果需要捕獲更高級(jí)別的異常,也就是在請(qǐng)求執(zhí)行過程中出現(xiàn)的任何異常(如在控制器的構(gòu)造函數(shù)中拋出異常),那么可以使用該種方式,代碼如下:
using log4net;
using log4net.Config;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Blog20180413
{
public class MvcApplication : System.Web.HttpApplication
{
static readonly ILog log = LogManager.GetLogger(typeof(MvcApplication));
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
XmlConfigurator.ConfigureAndWatch(new FileInfo(Server.MapPath("~/web.config")));
}
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
//Server.ClearError();
//這里記錄錯(cuò)誤日志信息
log.Error("MvcApplication 捕獲異常", exception);
//跳轉(zhuǎn)到指定的自定義錯(cuò)誤頁
Response.Redirect("/CustomErrorHandle/CustomErrorPage");
}
}
}
3、通過配置system.web->customErrors節(jié)點(diǎn) 實(shí)現(xiàn)自定義錯(cuò)誤頁
當(dāng)你的站點(diǎn)發(fā)生異常時(shí),如果你只是想簡(jiǎn)單的跳轉(zhuǎn)到一個(gè)自定義錯(cuò)誤頁面,而不是對(duì)異常進(jìn)一步處理時(shí),那么你可以簡(jiǎn)單的作如下配置操作即可:
需要在web.config中做如下配置:
<system.web> <customErrors mode="On" defaultRedirect="CustomErrorPage"> </customErrors> </system.web>
注意:這里的CustomErrorPage是一個(gè)視圖文件,放在Shared共享目錄下。
如果你注冊(cè)了HandleErrorAttribute異常過濾器到全局,那么在你的錯(cuò)誤頁中將能獲取到和異常相關(guān)的一些信息。但此時(shí)配置到defaultRedirect的值的必須是Error
也就是自定義錯(cuò)誤視圖頁面的名稱必須為Error.cshtml,并且放在Shared目錄,當(dāng)然,你也可以通過在創(chuàng)建HandleErrorAttribute全局過濾器的過程中,設(shè)置器View屬性,這樣你就可以不用講錯(cuò)誤視圖的名稱設(shè)置為Error了.如下:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
HandleErrorAttribute errorAttribute = new HandleErrorAttribute();
errorAttribute.View = "CustomErrorPage";
filters.Add(errorAttribute);
}
注冊(cè)HandleErrorAttribute(使用默認(rèn)的錯(cuò)誤視圖頁面文件名)
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
定義Error.cshtml視圖頁
@{
Layout = null;
}
@model HandleErrorInfo
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Error</title>
</head>
<body>
<div>
@*通過HandleErrorAttribute異常過濾器捕獲到的異常信息存儲(chǔ)在Model屬性中*@
@Model.Exception.Message
</div>
</body>
</html>
之所以通過注冊(cè)HandleErrorAttribute過濾器捕獲的異常在錯(cuò)誤頁中能獲取異常信息可以看HandleErrorAttribute類的內(nèi)部實(shí)現(xiàn),發(fā)現(xiàn)加載錯(cuò)誤視圖頁面的過程中,傳遞了一個(gè)HandleErrorInfo對(duì)象過去。
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
{
Exception innerException = filterContext.Exception;
if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))
{
string controllerName = (string) filterContext.RouteData.Values["controller"];
string actionName = (string) filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
ViewResult result = new ViewResult {
ViewName = this.View,
MasterName = this.Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
filterContext.Result = result;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
}
public string View
{
get
{
if (string.IsNullOrEmpty(this._view))
{
return "Error";
}
return this._view;
}
set =>
(this._view = value);
}
三、總結(jié)
總的來說,Application_Error方法用于處理針對(duì)請(qǐng)求管道級(jí)別的發(fā)生的異常錯(cuò)誤,而Mvc異常過濾器則只能處理在執(zhí)行action方法過程中出現(xiàn)的異常.能處理的范圍相對(duì)Application_Error較小,但在實(shí)際項(xiàng)目開發(fā)中,用Mvc異常過濾器處理異常相對(duì)會(huì)多一點(diǎn),因?yàn)槲覀兊墓δ軜I(yè)務(wù)往往體現(xiàn)在控制器的action方法執(zhí)行的過程中,也就是在這個(gè)過程中較容易產(chǎn)生異常。故開發(fā)中用Mvc異常過濾器就能適應(yīng)大部分的異常處理需求。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
asp.net Repeater 數(shù)據(jù)綁定的具體實(shí)現(xiàn)(圖文詳解)
此例子綁定的數(shù)據(jù)源為微軟在mssql2000中提供的Northwind數(shù)據(jù)庫(kù)中的表Categories。2013-07-07
ASP.NET插件uploadify批量上傳文件完整使用教程
這篇文章主要為大家詳細(xì)介紹了ASP.NET插件uploadify批量上傳文件完整使用教程,感興趣的小伙伴們可以參考一下2016-07-07
關(guān)于Metalama使用Fabric操作項(xiàng)目或命名空間的問題
Metalama是一個(gè)基于微軟編譯器Roslyn的元編程的庫(kù),可以解決我在開發(fā)中遇到的重復(fù)代碼的問題,這篇文章主要介紹了Metalama使用Fabric操作項(xiàng)目或命名空間,需要的朋友可以參考下2022-04-04
開源跨平臺(tái)運(yùn)行服務(wù)插件TaskCore.MainForm
這篇文章主要為大家詳細(xì)介紹了開源跨平臺(tái)運(yùn)行服務(wù)插件TaskCore.MainForm的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
a.sp.net清除ListBox的列表項(xiàng)(刪除所有項(xiàng)目)
在網(wǎng)上搜索相關(guān)資料,相當(dāng)多用戶有相同要求,一次移除ListBox的列表所有項(xiàng)2012-01-01
asp.net 身份驗(yàn)證(分目錄驗(yàn)證篇)
在上一篇博文《asp.net中的身份驗(yàn)證(最簡(jiǎn)單篇)》中的身份驗(yàn)證雖然很簡(jiǎn)單,但是有一個(gè)缺點(diǎn),就是訪問整個(gè)網(wǎng)站都必須要經(jīng)過身份驗(yàn)證,而事實(shí)上,很多網(wǎng)站都不會(huì)這么要求的。2009-05-05
.NET Framework攔截HTTP請(qǐng)求的實(shí)現(xiàn)
本文主要介紹了.NET Framework攔截HTTP請(qǐng)求的實(shí)現(xiàn),主要用于記錄 HTTP 信息,調(diào)試程序、分析程序性能等方面,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03

