.NET MVC全局異常處理(二) [TOC] 對上節的內容進行了補充 MVC過濾器Filter MVC有四種過濾器:Authorization、Exception、Action、Result,我們要用的的就是Exception異常過濾器 當我們新建一個MVC項目後,異常過濾器就已經自動在程式中註冊 ...
目錄
.NET MVC全局異常處理(二)
對上節的內容進行了補充
MVC過濾器Filter
MVC有四種過濾器:Authorization、Exception、Action、Result,我們要用的的就是Exception異常過濾器
當我們新建一個MVC項目後,異常過濾器就已經自動在程式中註冊了,先從上一節所說的全局配置文件開始,Global.asax這個文件中的Application_Start方法會在程式啟動時運行,其中的即預設註冊了全局過濾器,如圖
我們可以進入RegisterGlobalFilters方法查看,這個方法中預設註冊了一個異常處理過濾器,也就是說預設狀態的MVC程式發生異常時會被程式捕獲處理,處理方式是跳轉至錯誤頁面,也就是上一篇文章說的Layout文件夾下麵的Error頁
但使用異常過濾器有一個大前提是要在Web.config中打開自定義錯誤處理的設置,customErrors節點要設置為“On”,這一設置預設是關閉的,也就是說要手動加上才行
<system.web>
<compilation debug="true" targetFramework="4.6.1"/>
<httpRuntime targetFramework="4.6.1"/>
<customErrors mode="On">
</customErrors>
</system.web>
需要註意的是 404 錯誤,這種類型的異常並不會被過濾器捕獲
但是可以在web.config中添加節點進行自定義配置,跳轉到相應的頁面
<customErrors mode="On">
<error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
public class ErrorController : Controller
{
// GET: Error
public ActionResult Index()
{
return View();
}
public ActionResult CustomHttpError()
{
ViewBag.Message = "有錯誤";
//HandleErrorInfo
//ExceptionContext
return View();
}
public ActionResult NotFound()
{
return View();
}
}
自定義過濾器
MVC預設的異常過濾器可以滿足基本的需要,但是如果要對一些異常進行特殊處理就需要我們自定義過濾器的內容,可以通過重寫OnException方法達到這個目的
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
/* 調用基類的OnException方法,實現基礎的功能。
* 如果要完全的自定義,就不需要調用基類的方法
*/
base.OnException(filterContext);
/* 此處可進行記錄錯誤日誌,發送錯誤通知等操作
* 通過Exception對象和HttpException對象可獲取相關異常信息。
* Exception exception = filterContext.Exception;
* HttpException httpException = new HttpException(null, exception);
*/
}
}
示例代碼
public class MyErrorHandler : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
return;
var statusCode = (int) HttpStatusCode.InternalServerError;
if (filterContext.Exception is HttpException)
{
statusCode = filterContext.Exception.As<HttpException>().GetHttpCode();
}
else if (filterContext.Exception is UnauthorizedAccessException)
{
//to prevent login prompt in IIS
// which will appear when returning 401.
statusCode = (int)HttpStatusCode.Forbidden;
}
_logger.Error("Uncaught exception", filterContext.Exception);
var result = CreateActionResult(filterContext, statusCode);
filterContext.Result = result;
// Prepare the response code.
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = statusCode;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode)
{
var ctx = new ControllerContext(filterContext.RequestContext, filterContext.Controller);
var statusCodeName = ((HttpStatusCode) statusCode).ToString();
var viewName = SelectFirstView(ctx,
"~/Views/Error/{0}.cshtml".FormatWith(statusCodeName),
"~/Views/Error/General.cshtml",
statusCodeName,
"Error");
var controllerName = (string) filterContext.RouteData.Values["controller"];
var actionName = (string) filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
var result = new ViewResult
{
ViewName = viewName,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
};
result.ViewBag.StatusCode = statusCode;
return result;
}
protected string SelectFirstView(ControllerContext ctx, params string[] viewNames)
{
return viewNames.First(view => ViewExists(ctx, view));
}
protected bool ViewExists(ControllerContext ctx, string name)
{
var result = ViewEngines.Engines.FindView(ctx, name, null);
return result.View != null;
}
}