mvc原始碼解讀(14)-mvc四大過濾器之ExceptionFilter

風靈使發表於2018-07-10

這一章我們主要來講異常過濾器ExceptionFilter,廢話不多說,mvc3中預設的異常過濾器特性類是HandleErrorAttribute,該類的主要主要成員有:

public Type ExceptionType 
{
    getset
}
public string View 
{
    get 
    {
        if (string.IsNullOrEmpty(this._view)) 
        {
            return "Error";
        }
        return this._view;
    }
    set 
    {
        this._view = value;
    }
}
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;
        }
    }
}

其中ExceptionType表示異常的型別,預設是所有異常的基類Exception,表示會處理所有的標準異常。View屬性表示丟擲異常時該顯示什麼樣的檢視給使用者,如果每沒有自定義的View,系統預設輸出的是字串“Error”,OnException方法用於系統出現異常時呼叫的方法,我們看紅色程式碼這兩句:

filterContext.ExceptionHandled = true;

new HttpException(null, innerException).GetHttpCode() == 500

ExceptionHandled屬性是布林值,表示該丟擲的異常是否被處理了,true表示已經被處理,false表示沒有被處理,如果被處理過的異常,一定要將ExceptionHandled設定為true,防止父類或者更高階別的異常處理重複的處理改異常。而HttpCode=500表示會優先呼叫MVC框架自己的處理異常,然後將ExceptionHandled設定為true。我們先來看一段demo:

我們自定義一個異常類過濾器MyExceptionFilter,繼承自HandleErrorAttribute並重寫了OnException方法,實現方法如下:

public class MyExceptionFilter : HandleErrorAttribute 
{
    public override void OnException(ExceptionContext filterContext) 
    {
        if (!filterContext.ExceptionHandled && filterContext.Exception is DivideByZeroException) 
        {
            filterContext.Result = new RedirectResult("/MyException/ErrorView");
            filterContext.ExceptionHandled = true;
        }
        base.OnException(filterContext);
    }
}

我們建立一個MVC3的專案,建立一個MyException控制器,具體程式碼如下:

[MyExceptionFilter]
        public ActionResult Index() 
{
    int firstNumber = 10;
    int secondNumber = 0;
    int c = firstNumber / secondNumber;
    return View();
}
public ActionResult ErrorView() 
{
    return View();
}

ErrorView具體程式碼如下:

@{     Layout = null; }

<!DOCTYPE html>

<html> <head><title>ErrorView</title> </head> <body><div>

<p>這是一個異常頁面哦~~~~~</p>

</div> </body> </html>

執行結果如下:
這裡寫圖片描述

我們可以看到,在Index中出現異常的時候,執行了OnException方法,並將使用者的請求轉到了我們自定義的錯誤頁面,同時標記改異常已經處理過了,如果上文我們說到過,若是每個Controller都要貼上這個異常標籤,會很麻煩,因此我們可以在全域性檔案檔案註冊一個全域性的異常過濾器,具體如下:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{
    filters.Add(new HandleErrorAttribute());
    //filters.Add(new MyTestResultFiter() { FilterMessage="標誌全域性過濾器"});
    filters.Add(new MyExceptionFilter());
    //全域性的異常過濾器
}

,同時在配置檔案中設定i如下:

<system.web>
    <customErrors mode="On"></customErrors>
</system.web>

這是一種情況,我們來看另外一種情況,我們自己在try-catch中處理該異常,會有什麼結果呢,我們將Index裡面的方法稍作修改如下:

[MyExceptionFilter]
public ActionResult Index() 
{
    try 
    {
        int firstNumber = 10;
        int secondNumber = 0;
        int c = firstNumber / secondNumber;
    }
    catch (DivideByZeroException ex) 
    {
        HttpContext.Response.Write(ex.Message.ToString());
    }
    return View();
}

對應的index的View如下:

@{     Layout = null; }

<!DOCTYPE html>

<html><head><title>Index</title> </head> <body><div>        

<p>這個是我自己try-Catch到的異常哦~~~</p></div></body></html>

執行結果如下:
這裡寫圖片描述

我們可以看到,這一次他並沒有執行OnException方法,異常直接被Catch住了。try-Catchmvc內建的異常處理器到底有什麼樣的關係?望可以得到解釋~~

相關文章