本文實現對MVC異常處理功能,藉此來討論ASP.NET MVC中攔截器的使用方法。html
第一步:寫一個本身的異常過濾器,讓它繼承HandleErrorAttribute類 而後重寫OnException()這個方法 (注:HandleErrorAttribute 類已經繼承了FilterAttribute, IExceptionFilter這兩個接口,並實現了它們,因此這咱們只要繼承HandleErrorAttribute就能夠了)程序員
[csharp] view plaincopyweb
using System; 瀏覽器
using System.Collections.Generic; 服務器
using System.Linq; 框架
using System.Web; ide
using System.Web.Mvc; 性能
namespace Itcast.CMS.WebApp.Controllers.Filters 網站
{ spa
public class MyExceptionFilterAttribute : HandleErrorAttribute
{
Itcast.CMS.Common.LogHelper log = new Common.LogHelper();//建立一個log4net日記對象
public override void OnException(ExceptionContext filterContext)
{
//獲取或設置一個值,該值指示是否已處理異常。若是已處理異常,則爲 true;不然爲 false。
if (filterContext.ExceptionHandled==true)
{
HttpException httpException = filterContext.Exception as HttpException;
//爲何要特別強調500 由於MVC處理HttpException的時候,若是爲500 則會自動
//將其ExceptionHandled設置爲true,那麼咱們就沒法捕獲異常
if (httpException.GetHttpCode() == 500)
{
return;
}
}
//建立一個HttpException對象,使用filterContext.Exception來對它初始化(其實就是將filterContext.Exception轉換成HttpException類型)
HttpException httpExce = new HttpException(null, filterContext.Exception);
//HttpException httpExce = filterContext.Exception as HttpException;
if (httpExce != null)
{
if (httpExce.GetHttpCode() == 404)
{
HttpContext.Current.Response.Redirect("/Error/NotFound");//跳轉到404錯誤頁面
}
else if (httpExce.GetHttpCode() == 500)
{
//也能夠這樣寫
filterContext.HttpContext.Response.Redirect("/Error/ServerError");//跳轉到500服務器錯誤頁面
}
}
//調用log4net來記錄日記
log.Error("錯誤:" + filterContext.Exception.Message, filterContext.Exception);
filterContext.ExceptionHandled = true; //將異常設置爲已處理
}
}
}
第二步:將本身剛剛寫的過異常濾器註冊到MVC的全局過濾器中去。只要到App_Start這個文件夾下的FilterConfig.cs文件中註冊一下就能夠,
將默認的 filters.Add(new HandleErrorAttribute()); 這段代碼 替換爲filters.Add(new MyExceptionFilterAttribute()); 具體代碼以下
[csharp] view plaincopy
using Itcast.CMS.WebApp.Controllers.Filters;
using System.Web;
using System.Web.Mvc;
namespace Itcast.CMS.WebApp
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyExceptionFilterAttribute());
}
}
}
作好以上兩步,當MVC中有異常的時候,就會自動跳轉到本身的過濾器中進行處理了。(注:不須要在類,或者方法前面加[MyExceptionController])只要作好前面兩步就能夠了
其實有的時候報404錯誤,也就是在路由階段就沒有經過,也就是沒有到達控制器,因此沒法進入到咱們的過濾器。(去網上查了一下,都說404不是屬 於一個異常,僅僅是路徑錯誤,這時候只要去Web.cofig配置文件中,配置一下,當出現404錯誤的時候,就跳轉到咱們自定義的錯誤頁去)
[html] view plaincopy
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<!--定義友好的錯誤,出錯默認導向到 咱們定義好的友好錯誤頁面 -->
<!--mode 屬性:mode="On"的時候就表示對因此訪問者都顯示定製錯誤頁;mode="Off"就表示關閉定製的錯誤頁,頁面錯誤的時候將本地和遠程用戶都會 看到詳細的錯誤信息;mode="RemoteOnly"就表示本地用戶將看到詳細錯誤信息(這裏的本地的意思即:你直接登錄網站服務器上),而遠程用戶 將會看到程序員定製的錯誤頁。因此通常狀況下咱們都建議將mode屬性設爲RemoteOnly-->
<!--RedirectMode 屬 性:獲取或設置一個值,該值指示在將用戶重定向到自定義錯誤頁面時,是否應更改請求的 URL。默認值爲 ResponseRedirect。如 果 RedirectMode 屬性設置爲 ResponseRedirect,則將用戶重定向到該錯誤頁面,而且原始 URL 更改成該錯誤頁面 的 URL。若是 RedirectMode 屬性設置爲 ResponseRewrite,則將用戶定向到錯誤頁面,而且不更改瀏覽器中的原 始 URL。【ResponseRedirect其實就是Response.Redirect;而ResponseRewrite其實就是 Server.Transfer】 -->
<!--defaultRedirect屬性:應用程序在發生錯誤時重定向到的默認URL-->
<!--<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="/Error/notfound">-->
<!--在它下面還能夠分的很詳細,能夠針對一些錯誤碼來指向咱們針對這些錯誤碼而定製的頁面-->
<!--<error statusCode="403" redirect="/Error/403" />-->
<!--<error statusCode="404" redirect="/Error/404" />-->
<!--</customErrors>-->
<customErrors mode="On" >
<error statusCode="404" redirect="/Error/notfound"/><!--出現404錯誤的時候跳轉到Error控制器下的notfound方法-->
</customErrors>
</system.web>
</configuration>
附贈logHelper.cs
[csharp] view plaincopy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Itcast.CMS.Common
{
public class LogHelper
{
private log4net.ILog log = null;
public LogHelper()
{
//若是Web.config配置文件中的key爲log4net的value值爲1,就表示log4net的配置文件是做爲一個單獨文件進行配置的,
if (System.Configuration.ConfigurationManager.AppSettings["log4net"].ToString() == "1")
{
//那麼我就獲取log4net的配置文件,並將它加載到咱們的項目中去
string filePath = System.Configuration.ConfigurationManager.AppSettings["log4netPath"].ToString();
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
//Getlogger()靜態方法,用來檢索框架裏是否存在logger對象,若是不存在就建立一個名字爲logger的對象
log4net.Config.XmlConfigurator.Configure(file);
}
else
{
log4net.Config.XmlConfigurator.Configure();
}
log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
}
/// <summary>
/// 程序運行的過程當中的,通常信息能夠調用此方法記錄日記
/// </summary>
/// <param name="info"></param>
public void Info(string info)
{
if (log.IsInfoEnabled)
{
log.Info(info);
}
}
/// <summary>
/// 程序運行的過程當中的,通常信息能夠調用此方法記錄日記
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public void Info(string info, Exception ex)
{
if (log.IsInfoEnabled)
{
log.Info(info, ex);
}
}
/// <summary>
/// 程序出現錯誤的時候調用此方法記錄日記(通常用在出現了異常之後)
/// </summary>
/// <param name="info"></param>
public void Error(string info)
{
if (log.IsErrorEnabled)
{
log.Error(info);
}
}
/// <summary>
/// 程序出現錯誤的時候調用此方法記錄日記(通常用在出現了異常之後)
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public void Error(string info, Exception ex)
{
if (log.IsErrorEnabled)
{
log.Error(info, ex);
}
}
/// <summary>
/// 程序員以爲任何有利於程序在調試時更詳細的瞭解系統運行狀態的信息,好比變量的值等等,均可以調用此方法記錄到日記
/// </summary>
/// <param name="info"></param>
public void Debug(string info)
{
if (log.IsDebugEnabled)
{
log.Debug(info);
}
}
/// <summary>
/// 程序員以爲任何有利於程序在調試時更詳細的瞭解系統運行狀態的信息,好比變量的值等等,均可以調用此方法記錄到日記
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public void Debug(string info, Exception ex)
{
if (log.IsDebugEnabled)
{
log.Debug(info, ex);
}
}
/// <summary>
/// 程序出現警告時調用此方法記錄日記(程序出現警告不會使程序出現異常,可是可能會影響程序性能)
/// </summary>
/// <param name="info"></param>
public void Warn(string info)
{
if (log.IsWarnEnabled)
{
log.Warn(info);
}
}
/// <summary>
/// 程序出現警告時調用此方法記錄日記(程序出現警告不會使程序出現異常,可是可能會影響程序性能)
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public void Warn(string info, Exception ex)
{
if (log.IsWarnEnabled)
{
log.Warn(info, ex);
}
}
/// <summary>
/// 程序出現特別嚴重的錯誤,通常是在應用程序崩潰的時候調用此方法記錄日記
/// </summary>
/// <param name="info"></param>
public void Fatal(string info)
{
if (log.IsFatalEnabled)
{
log.Fatal(info);
}
}
/// <summary>
/// 程序出現特別嚴重的錯誤,通常是在應用程序崩潰的時候調用此方法記錄日記
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public void Fatal(string info, Exception ex)
{
if (log.IsFatalEnabled)
{
log.Fatal(info, ex);
}
}
}
}