ASP.NET MVC 4でカスタムエラーページを機能させる方法


247

500、404、403のカスタムエラーページを表示したいのですが、次のようにしています。

  1. 次のように、web.configでカスタムエラーを有効にしました。

    <customErrors mode="On" 
                  defaultRedirect="~/Views/Shared/Error.cshtml">
    
        <error statusCode="403" 
               redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
    
        <error statusCode="404" 
               redirect="~/Views/Shared/FileNotFound.cshtml" />
    
    </customErrors>
  2. 次のようHandleErrorAttributeに、FilterConfigクラスのグローバルアクションフィルターとして登録されます。

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomHandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
  3. 上記の各メッセージのカスタムエラーページを作成しました。500のデフォルトの1つは、箱から出してすぐに使用できます。

  4. 各カスタムエラーページビューで、ページのモデルが次のように宣言されている System.Web.Mvc.HandleErrorInfo

500の場合、カスタムエラーページが表示されます。他の人にとってはそうではありません。

何か足りないものはありますか?

これはOnExceptionHandleErrorAttributeクラスのメソッドのコードを読み、500しか処理していないため、カスタムエラーの表示がすべてではないようです。

他のエラーを処理するにはどうすればよいですか?


21
この設定の奇妙な点は、コントローラーアクションではなくビューにリダイレクトすることです。たとえば、これらのビューをレンダリングしてモデルに渡すのは誰ですか?考えてただけ。
オリバー

2
ここでの回答のほとんどは、すべてのケースを処理するわけではないか、またはWebサーバーが「誤った」方法で応答するようにします。つまり、エラー応答を返すのではなく、エラーページにリダイレクトします。サーバーがWebサーバーに期待される方法で応答することに関心がある場合は、それに関するかなり詳細な記事がここにあります:benfoster.io/blog/aspnet-mvc-custom-error-pages。ここでの回答ほど簡単ではないので注意してください。簡単な回答が必要な場合は、代わりに以下のいずれかを使用してください。
rdans 2016年

1
これは、asp.netのエラー処理のさまざまな手法に関する別の優れた記事です。dusted.codes/…
Godsayah

回答:


352

私の現在のセットアップ(MVC3では、それでも適用されると思います)はを持つことに依存しているErrorControllerため、以下を使用します。

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

また、コントローラーには以下が含まれます。

public class ErrorController : Controller
{
    public ViewResult Index()
    {
        return View("Error");
    }
    public ViewResult NotFound()
    {
        Response.StatusCode = 404;  //you may want to set this to 200
        return View("NotFound");
    }
}

そして、ビューは、それらを実装する方法とまったく同じです。ただし、アプリケーションがデバッグモードの場合にスタックトレースとエラー情報を表示するために、少しロジックを追加する傾向があります。したがって、Error.cshtmlは次のようになります。

@model System.Web.Mvc.HandleErrorInfo
@{
    Layout = "_Layout.cshtml";
    ViewBag.Title = "Error";
}
<div class="list-header clearfix">
    <span>Error</span>
</div>
<div class="list-sfs-holder">
    <div class="alert alert-error">
        An unexpected error has occurred. Please contact the system administrator.
    </div>
    @if (Model != null && HttpContext.Current.IsDebuggingEnabled)
    {
        <div>
            <p>
                <b>Exception:</b> @Model.Exception.Message<br />
                <b>Controller:</b> @Model.ControllerName<br />
                <b>Action:</b> @Model.ActionName
            </p>
            <div style="overflow:scroll">
                <pre>
                    @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
</div>

7
このPabloのGlobal.asaxのApplication_Errorに何かを入れる必要がありましたか?
アリシア2013

12
コントローラーのコードは私の経験では実行されていないようです。MVC4-別のコントローラーでSystem.Exceptionをスローすると、Error.cshtmlファイルがレンダリングされますが、ErrorControllerはレンダリングされません。これを経験している人はいますか?
Nilzor 2014年

53
これは役に立ったが他のコンテキストが必要な人のために。<customErrors>タグは、web.configの<system.web>内にあります。
gooberverse 2014年

7
他の人のための更新 -どうやら私redirectMode="ResponseRewrite"CustomerErrors要素にあったので私の問題が起こっていた
KyleMit 14

42
神の愛のために//you may want to set this to 200コードにあるコメントを無視してください。やめてください!
認知症

40

私はパブロソリューションを実行しましたが、常にエラーが発生しました(MVC4)

ビュー「エラー」またはそのマスターが見つからなかったか、検索された場所をサポートするビューエンジンがありません。

これを取り除くには、行を削除します

 filters.Add(new HandleErrorAttribute());

FilterConfig.cs


私はこれを解決するためにあらゆるところを見ました。これでようやく答えが出ました。なぜそれが行われていたのかはわかっていましたが、他の人が言ったことを徹底的に考えることなくして、私には一体何もできませんでした。これを指摘してくれてありがとうと言うとき、私は360Airwalkの苦痛を分かち合うと思います。伝説!
アダム

これは1つのオプションであり、エラーコントローラは正常に動作します。しかし、FilterConfig.csにフィルターを登録すると、共有コントローラーと元のコントローラーのビューフォルダーでError.cshtmlが検索されるようです。Error.cshtmlをカスタムErrorControllerが機能するもの以外に変更すると、しかし、この登録を追加できる場所があり、それはglobal.asax.csです。上記の行をglobal.asax.csのRegisterGlobalFilters(GlobalFilterCollection filters)関数に追加し、FilterConfig.csから削除すると、機能します。
isaolmez

フィルター登録の順番に関係していると思います。エラーコントローラーを保持し、フィルター登録をglobal.asax.csに移動します。public static void RegisterGlobalFilters(GlobalFilterCollection filters){filters.Add(new HandleErrorAttribute()); }
isaolmez

24

私は、他の投稿されたソリューションよりもコーディングが少なくて済むようなことをしています。

まず、私のweb.configには、次のものが含まれています。

<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
   <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
   <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>

また、コントローラー(/Controllers/ErrorPageController.cs)には以下が含まれます。

public class ErrorPageController : Controller
{
    public ActionResult Oops(int id)
    {
        Response.StatusCode = id;

        return View();
    }
}

そして最後に、ビューには次のものが含まれます(簡略化のために省略されていますが、次のようになる場合があります)。

@{ ViewBag.Title = "Oops! Error Encountered"; }

<section id="Page">
  <div class="col-xs-12 well">
    <table cellspacing="5" cellpadding="3" style="background-color:#fff;width:100%;" class="table-responsive">
      <tbody>
        <tr>
          <td valign="top" align="left" id="tableProps">
            <img width="25" height="33" src="~/Images/PageError.gif" id="pagerrorImg">
          </td>
          <td width="360" valign="middle" align="left" id="tableProps2">
            <h1 style="COLOR: black; FONT: 13pt/15pt verdana" id="errortype"><span id="errorText">@Response.Status</span></h1>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth"><font style="COLOR: black; FONT: 8pt/11pt verdana">Possible causes:</font>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth2">
            <font style="COLOR: black; FONT: 8pt/11pt verdana" id="LID1">
                            <hr>
                            <ul>
                                <li id="list1">
                                    <span class="infotext">
                                        <strong>Baptist explanation: </strong>There
                                        must be sin in your life. Everyone else opened it fine.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Presbyterian explanation: </strong>It's
                                        not God's will for you to open this link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong> Word of Faith explanation:</strong>
                                        You lack the faith to open this link. Your negative words have prevented
                                        you from realizing this link's fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Charismatic explanation: </strong>Thou
                                        art loosed! Be commanded to OPEN!<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Unitarian explanation:</strong> All
                                        links are equal, so if this link doesn't work for you, feel free to
                                        experiment with other links that might bring you joy and fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Buddhist explanation:</strong> .........................<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Episcopalian explanation:</strong>
                                        Are you saying you have something against homosexuals?<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Christian Science explanation: </strong>There
                                        really is no link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Atheist explanation: </strong>The only
                                        reason you think this link exists is because you needed to invent it.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Church counselor's explanation:</strong>
                                        And what did you feel when the link would not open?
                                    </span>
                                </li>
                            </ul>
                            <p>
                                <br>
                            </p>
                            <h2 style="font:8pt/11pt verdana; color:black" id="ietext">
                                <img width="16" height="16" align="top" src="~/Images/Search.gif">
                                HTTP @Response.StatusCode - @Response.StatusDescription <br>
                            </h2>
                        </font>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

それはそれと同じくらい簡単です。より詳細なエラー情報を提供するように簡単に拡張できますが、ELMAHがそれを処理してくれます。通常、statusCodeとstatusDescriptionだけで十分です。


"〜/ ErrorPage / Oops / 404"の.configファイルのリダイレクトは、おそらく "〜/ ErrorPage / Oops?404"であるべきだと思いますか?少なくともそれが私にとってはうまくいった。多分それはルーティングに依存します。
Josh Sutterfield、

IISによってスローされたエラーをシミュレートする方法。500または504にしてください。ASP.NetMVCで行うこと
2017年

12

ここにはいくつかのステップが混同されているようです。私が最初からやったことを先に進めます。

  1. ErrorPageコントローラーを作成する

    public class ErrorPageController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult Oops(int id)
        {
            Response.StatusCode = id;
            return View();
        }
    }
  2. これら2つのアクションのビューを追加します(右クリック-> [ビューの追加])。これらは、ErrorPageと呼ばれるフォルダに表示されます。

  3. 内部をApp_Start開いFilterConfig.csて、エラー処理フィルターをコメント化します。

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // Remove this filter because we want to handle errors ourselves via the ErrorPage controller
        //filters.Add(new HandleErrorAttribute());
    }
  4. web.config内で、次の<customerErrors>エントリを追加します。System.Web

    <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
        <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
        <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
    </customErrors>
  5. テスト(もちろん)。コードで未処理の例外をスローし、ID 500のページに移動することを確認してから、存在しないページへのURLを使用して404を確認します。


私はこのエラーAn exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.を受け取りました。私があなたのコードから拾ったすべてはweb.configファイルにあります、私は追加し<error redirect = "~/ControllerName/ActionName" statusCode="404"/>、それはうまくいきました:)コードの残りは@Pabloの答えからのものでした。私はMVC 5とエンティティフレームワーク6を使用しています。削除しませんでしfilters.Add(new HandleErrorAttribute())FilterConfig.cs
sumedha

IISによってスローされたエラーをシミュレートする方法。500または504にしてください。ASP.NetMVCで行うこと
2017年

また、未処理の例外をスローする方法(ステップ5)。私はコーディングに不慣れなので、ガイドしてください。
アンブレイカブル2017年

それでもうまくいきませんか?ルーティングについてはどうですか?エラーページのルーティングも追加する必要がありますか?私はページをヒットした場合:ローカルホスト:84 /エンフォーサ/何とか:私はにリダイレクトはlocalhost:84 /エンフォーサ/エンフォーサ/エラー/ NOTFOUND aspxerrorpath = / ...? Asp.NETが提供する標準エラー・ページのようなエラーページルックス。何か案は?
Radek Strugalski 2017

webconfigのcustomerrors要素はこれを処理する必要があります。(プロジェクトで作成された)デフォルトのルートコードは問題なく機能するはずです。
VictorySabre 2017

11

Global.asax.csファイルを使用することをお勧めします。

 protected void Application_Error(Object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    if (exception is HttpUnhandledException)
    {
        Server.Transfer("~/Error.aspx");
    }
    if (exception != null)
    {
        Server.Transfer("~/Error.aspx");
    }
    try
    {
        // This is to stop a problem where we were seeing "gibberish" in the
        // chrome and firefox browsers
        HttpApplication app = sender as HttpApplication;
        app.Response.Filter = null;
    }
    catch
    {
    }
}

1
MVCでServer.Transfer()を実行できるとは思いませんでした。OPに混合サイトがあると思いますか?
2014年

1
なぜmvcでApplication_Errorを使用する必要があるのですか?[handleerror]属性のようなオプションがあり、リダイレクトURLオプションがあります。application_errorにはそれに対する特定の利点がありますか?
Kurkula

MVCではHandleErrorAttributeを使用する必要があり、OnExceptionメソッドをオーバーライドすることで、はるかに優れた方法でそれらを処理できます
Kumar Lachhani

7

maxspanによって投稿された答えに基づいて、私は最小限をまとめました GitHubにサンプルプロジェクトをすべての機能部品を示しました。

基本的にはApplication_Errorglobal.asax.csにメソッドを追加して例外をインターセプトし、カスタムエラーページにリダイレクトする(正確には、リクエストを転送する)機会を提供します。

    protected void Application_Error(Object sender, EventArgs e)
    {
        // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4
        // for additional context on use of this technique

        var exception = Server.GetLastError();
        if (exception != null)
        {
            // This would be a good place to log any relevant details about the exception.
            // Since we are going to pass exception information to our error page via querystring,
            // it will only be practical to issue a short message. Further detail would have to be logged somewhere.

            // This will invoke our error page, passing the exception message via querystring parameter
            // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above.
            // As an alternative, Response.Redirect could be used instead.
            // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 )
            Server.TransferRequest("~/Error?Message=" + exception.Message);
        }

    }

エラーコントローラー:

/// <summary>
/// This controller exists to provide the error page
/// </summary>
public class ErrorController : Controller
{
    /// <summary>
    /// This action represents the error page
    /// </summary>
    /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param>
    /// <returns></returns>
    public ActionResult Index(string Message)
    {
        // We choose to use the ViewBag to communicate the error message to the view
        ViewBag.Message = Message;
        return View();
    }

}

エラーページビュー:

<!DOCTYPE html>

<html>
<head>
    <title>Error</title>
</head>
<body>

    <h2>My Error</h2>
    <p>@ViewBag.Message</p>
</body>
</html>

他には何も無効にする/削除する以外に、関与しないfilters.Add(new HandleErrorAttribute())FilterConfig.cs

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute()); // <== disable/remove
    }
}

実装は非常に簡単ですが、このアプローチで見られる欠点の1つは、クエリ文字列を使用して例外情報をターゲットのエラーページに配信することです。


3

すべてをセットアップしましたが、ローカルの開発サーバーではすべて正常に機能しているにもかかわらず、ステージングサーバーでステータスコード500の適切なエラーページを表示できませんでした。

私を助けてくれたRick Strahlのこのブログ投稿を見つけました。

Response.TrySkipIisCustomErrors = true;カスタムエラー処理コードに追加する必要がありました。


@ Shaun314あなたはそのコードをどこに置くのですか?リクエストを処理するアクション。そのブログ投稿で例を見ることができます。
DCShannon

2

これが私の解決策です。[ExportModelStateToTempData] / [ImportModelStateFromTempData]を使用するのは不快です。

〜/ Views / Home / Error.cshtml:

@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<hr/>

<div style="min-height: 400px;">

    @Html.ValidationMessage("Error")

    <br />
    <br />

    <button onclick="Error_goBack()" class="k-button">Go Back</button>
    <script>
        function Error_goBack() {
            window.history.back()
        }
    </script>

</div>

〜/ Controllers / HomeController.sc:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Error()
    {
        return this.View();
    }

    ...
}

〜/ Controllers / BaseController.sc:

public class BaseController : Controller
{
    public BaseController() { }

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            if (filterContext.Controller.TempData.ContainsKey("Error"))
            {
                var modelState = filterContext.Controller.TempData["Error"] as ModelState;
                filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) });
                filterContext.Controller.TempData.Remove("Error");
            }
        }
        if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
        {
            if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error"))
            {
                filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"];
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

〜/ Controllers / MyController.sc:

public class MyController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Details(int id)
    {
        if (id != 5)
        {
            ModelState.AddModelError("Error", "Specified row does not exist.");
            return RedirectToAction("Error", "Home");
        }
        else
        {
            return View("Specified row exists.");
        }
    }
}

プロジェクトの成功を祈っています;-)


2

global.csをハックしたり、HandleErrorAttributeをいじったり、Response.TrySkipIisCustomErrorsを実行したり、Application_Errorを接続したりすることなく、エラーを正しく機能させることができます。

system.web(通常、オン/オフ)

<customErrors mode="On">
  <error redirect="/error/401" statusCode="401" />
  <error redirect="/error/500" statusCode="500" />
</customErrors>

そしてsystem.webServerに

<httpErrors existingResponse="PassThrough" />

これで、物事は期待どおりに動作し、ErrorControllerを使用して必要なものを表示できます。


IISによってスローされたエラーをシミュレートする方法。500または504にしてください。ASP.NetMVCで行うこと
2017年

@Unbreakableは、コードを一時的に変更して例外をスローします。
theycallmemorty 2017

私にとって違いはありませんでした。例外または404 not foundエラーでカスタムエラーページが表示されません。
pnizzle

0

パーティーに遅れてきたようですが、こちらも要チェックです。

したがって、system.webreturn HttpNotFound()などのアプリケーション内の例外をキャッシュするために

  <system.web>
    <customErrors mode="RemoteOnly">
      <error statusCode="404" redirect="/page-not-found" />
      <error statusCode="500" redirect="/internal-server-error" />
    </customErrors>
  </system.web>

そして、でsystem.webServerIISによって摘発されたとasp.netの枠組みに自分の道を作っていなかったエラーをキャッチアップのための

 <system.webServer>
    <httpErrors errorMode="DetailedLocalOnly">
      <remove statusCode="404"/>
      <error statusCode="404" path="/page-not-found" responseMode="Redirect"/>
      <remove statusCode="500"/>
      <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/>
  </system.webServer>

最後の1つでは、クライアントの応答を心配している場合は、を変更しresponseMode="Redirect"responseMode="File"静的なhtmlファイルを提供します。これは、200の応答コードを持つわかりやすいページを表示するためです。


0

web.configで、以下のようにsystem.webserverタグの下にこれを追加します。

<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/>
  <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/>
</httpErrors>

としてコントローラを追加し、

public class ErrorController : Controller
{
    //
    // GET: /Error/
    [GET("/Error/NotFound")]
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;

        return View();
    }

    [GET("/Error/ErrorPage")]
    public ActionResult ErrorPage()
    {
        Response.StatusCode = 500;

        return View();
    }
}

そして彼らの尊敬される見解を加えると、これは間違いなくすべての人に当てはまると思います。

私が見つけたこのソリューション:海王星センチュリー

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.