ASP.NET MVC 客製錯誤畫面實務 (ASP.NET MVC Custom Error Practice)

2022-08-20

介紹在 ASP.NET MVC 開發上,如何藉由設定 customErrors 以及 httpErrors 將應用程式運行過程的錯誤畫面進行客製,提升使用者體驗 😊

logo

說明

良好的客製化錯誤頁面具備的特性:

  1. 在本機顯示具體的錯誤訊息
  2. 在遠距用戶端顯示客製化的錯誤訊息
  3. 不使用重導 (302),而是顯示錯誤的內容並搭配正確的 HTTP Status Code

圖解 ASP.NET MVC Custom Error

ASP.NET MVC 預設在 Filters 上已註冊 HandleError,因此預設上發生在 ASP.NET 的 Http Status Code 500 都會交由 HandleErrorAttribute 所處理。

若取消這個註冊,則會恢復到由 .NET Error (customErrors) 進行處理。此外如果在 HandleErrorAttribute 再度發生錯誤,也會交回由 .NET Error (customErrors) 進行處理。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

而如果 existingResponseReplace,則所有由 .NET Error (customErrors) 負責的錯誤都會交由 IIS Error (httpErrors) 所負責!

造成錯誤的亂源:

Route Error
ASP.NET MVC 路由發生的錯誤,例如不存在的路由 /Home/a,由 ASP.NET 處理錯誤
Throw New Exception
拋出例外,會引發 HttpStatusCode 500,由 ASP.NET 處理錯誤,預設會被 CustomError 處理
Throw New Exception(404, message)
拋出例外,並且指定 HttpStatusCode 404,由 ASP.NET 處理錯誤,預設不會被 CustomError 處理
HttpStatusCodeResult
Controller 可以回應的 Result,可以動態選擇要回應的 Http Status Code,由 IIS 處理錯誤
Http NotFound
Controller 可以回應的 Result (相當於 HttpStatusCodeResult 404) 由 IIS 處理錯誤
1.jpg / 1.asp / 1.html
不存在的資源
1.aspx / 1.ashx / 1.asmx
不存在的 ASP.NET 負責解析的資源

httpErrors 是 IIS 7 以後出現的功能,因此要使用 Integration Pipeline 才能夠使用。

實戰 ASP.NET MVC 客製錯誤

這是預熱菜範例,隨時可以端上桌,加入到每個專案使用,或者是每一個新建立的專案都應該進行的設定。

為了兼具客製化錯誤頁面的良好特性,採用在專案中加入 Error Controller 的方式處理,並且整合 customErrors 與 httpErrors 的使用。

首先取消 FilterConfig.cs 的 HandleErrorAttribute 註冊。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

接著在 web.config 進行設定:

<system.web>
  <customErrors mode="On" defaultRedirect="~/Error">
    <error statusCode="404" redirect="~/Error/NotFound" />
  </customErrors>
</system.web>

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" prefixLanguageFilePath=""
            path="/Error/NotFound" responseMode="ExecuteURL" />
  </httpErrors>
</system.webServer>

最後加入 Controller 以及相關的 View:

ErrorController.cs

public class ErrorController : Controller
{
    // GET: Error
    public ActionResult Index()
    {
        return View();
    }

    // GET: Error/NotFound
    public ActionResult NotFound(){
        Response.Status = "404 Not Found";
        Response.StatusCode = 404;
        Response.StatusDescription = "Not Found!";
        return View();
    }

    // GET: Error/Gone
    public ActionResult Gone()
    {
        Response.Status = "410 Gone";
        Response.StatusCode = 410;
        Response.StatusDescription = "Gone!";
        return View("NotFound");
    }

    public ActionResult StatusCode(int statuscode)
    {
        return new HttpStatusCodeResult(statuscode);
    }

    public ActionResult HttpNotFoundAction()
    {
        return HttpNotFound();
    }

    [HandleError]
    public ActionResult ThrowException()
    {
        throw new HttpException();
        return View();
    }
}

參考資料

HandleErrorAttribute.cs | GitHub

HTTP Errors | learn.microsoft

Yowkow's Notes 所分享的 httpErrors 與 customErrors 在 ASP.NET MVC 與 ASP.NET WEB API 中的處理方式

軟體主廚的程式料理廚房所分享的 個人常用的 ASP.NET MVC 自訂 HTTP 回應碼畫面的套路

相關連結

ASP.NET MVC 從無到有打造一個應用系統

Visual Studio 入門教學