The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

修復 Visual Studio 中 ASP.NET MVC 5 專案範本的 Error.cshtml 檔案內容

從 Visual Studio 2017 一直到 Visual Studio 2022 的 ASP.NET MVC 5 專案範本,其 /Views/Shared/Error.cshtml 檢視 (View) 檔案內容都是錯誤的。之前在講授 ASP.NET MVC 5 課程的時候,每次都要自己 Google 以下這個檔案的完整範例,或是去翻找我之前寫過的版本。今天這篇文章特別將該檔案的問題做個說明,並且提供完整的範例程式,方便我日後快速查找到正確的 Error View 檔案內容。

問題描述

當你透過 Visual Studio 建立 ASP.NET MVC 5 專案範本,其 /Views/Shared/Error.cshtml 檔案內容如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width" />
    <title>錯誤</title>
</head>
<body>
    <hgroup>
        <h1>錯誤。</h1>
        <h2>處理您的要求時發生錯誤。</h2>
    </hgroup>
</body>
</html>

注意:這裡的 <hgroup> 並不是合法的 HTML5 標籤(Tag),所以應該移除才對!🔥

若你的 Web.config 的 <customErrors> 設定為 mode="On" 的話:

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

當你的 Controller 出現任何例外狀況時,呈現的 HTML 會連同 Layout 與 Error 檢視頁面的內容一起輸出,結果長這樣:


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> - 我的 ASP.NET 應用程式</title>
    <link href="/Content/bootstrap.css" rel="stylesheet"/>
<link href="/Content/site.css" rel="stylesheet"/>

    <script src="/Scripts/modernizr-2.8.3.js"></script>

</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">應用程式名稱</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="/">Home</a></li>
                    <li><a href="/Home/About">關於</a></li>
                    <li><a href="/Home/Contact">連絡人</a></li>
                </ul>
            </div>
        </div>
    </div>
    <div class="container body-content">

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width" />
    <title>錯誤</title>
</head>
<body>
    <hgroup>
        <h1>錯誤。</h1>
        <h2>處理您的要求時發生錯誤。</h2>
    </hgroup>
</body>
</html>

        <hr />
        <footer>
            <p>&copy; 2022 - 我的 ASP.NET 應用程式</p>
        </footer>
    </div>

    <script src="/Scripts/jquery-3.4.1.js"></script>

    <script src="/Scripts/bootstrap.js"></script>


</body>
</html>

這意味著最終的 HTML 竟然出現了兩份,每次看到這種結果都覺得很傻眼,微軟怎麼可以放任這個問題這麼多年?因為 ASP.NET MVC 5 已經不會再有新版本了!

這個問題到了 ASP.NET Core MVC 已經有解決。

解決方案

所以,正確的 /Views/Shared/Error.cshtml 檔案內容應該是這樣的:

@model HandleErrorInfo

<h1>錯誤。</h1>
<h2>處理您的要求時發生錯誤。</h2>

這裡的 @model HandleErrorInfo 是當 Error 錯誤頁面顯示時,可以取得錯誤資訊的 Model 型別,在 Error 這個 View 檢視頁面中,就是應該使用這個 Model 來取得例外資訊。例如,你可以使用以下方法取得例外的訊息內容:

@model HandleErrorInfo

<h1>錯誤。</h1>
<h2>處理您的要求時發生錯誤。</h2>

<pre>@Model.Exception.Message</pre>

如果想要參考更完整的錯誤訊息顯示範例,可以參考以下程式碼片段:

@model HandleErrorInfo

<h1>錯誤。</h1>
<h2>處理您的要求時發生錯誤。</h2>

<ul>
    <li>
        ControllerName

        <blockquote>@Model.ControllerName</blockquote>
    </li>
    <li>
        ActionName

        <blockquote>@Model.ActionName</blockquote>
    </li>
    <li>
        Exception

        <blockquote><pre>@Model.Exception.ToString()</pre></blockquote>
    </li>
    @{
        if (Model.Exception is null)
        {
            <li>
                InnerException

                <blockquote>@(Model.Exception.InnerException?.ToString())</blockquote>
            </li>
        }
    }

    @{
        if (Model.Exception is System.Data.Entity.Validation.DbEntityValidationException ex)
        {
            <li>
                DbEntityValidationException

                <blockquote>

                    <ol>
                        @foreach (var eves in ex.EntityValidationErrors)
                        {
                            foreach (var ves in eves.ValidationErrors)
                            {
                                <li>@(ves.PropertyName + ": " + ves.ErrorMessage))</li>
                            }
                        }
                    </ol>

                </blockquote>
            </li>
        }
    }

    <li>
        User

        <blockquote>@User.Identity.Name</blockquote>
    </li>

    <li>
        Url

        <blockquote>@Request.Url</blockquote>
    </li>

    <li>
        SessionID

        <blockquote>@Session.SessionID</blockquote>
    </li>

</ul>

相關連結

留言評論