asp.net MVC3のカスタムエラーページ


144

MVC3ベースのWebサイトを開発していて、エラーを処理するためのソリューションと、エラーの種類ごとにカスタムビューをレンダリングする方法を探しています。そこで、「アクション」が「インデックス」(一般的なエラーページ)である「エラー」コントローラがあり、このコントローラが「Handle500」や「HandleActionNotFound」などのユーザーに表示される可能性のあるエラーに対するアクションをさらにいくつか持っているとします。

したがって、Webサイトで発生する可能性のあるすべてのエラーは、この「エラー」コントローラ(例:「コントローラ」または「アクション」が見つからない、500、404、dbExceptionなど)によって処理される可能性があります。

サイトマップファイルを使用して(ルーティングではなく)Webサイトパスを定義しています。

この質問はすでに回答されています。これはGweebzへの返信です

私の最後のapplicaiton_errorメソッドは次のとおりです。

protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
    Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
    try
    {
        var exception = Server.GetLastError();

        Log.Logger.Error("unhandled exception: ", exception);

        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }
    catch (Exception e)
    {
        //if Error controller failed for same reason, we will display static HTML error page
        Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
        Response.TransmitFile("~/error.html");
    }
}
}

これをサポートするには、web.configにどのような設定を含める必要がありますか?おそらくあなたはどんなhttperrors設定も含めないでしょうか?
philbird 2011年

forums.asp.net/p/1782402/4894514.aspx/…512バイト未満の場合、IEがエラーページを表示しないなどの素晴らしいヒントがあります
RickAndMSFT

回答:


201

カスタムエラーの処理方法の例を次に示します。ErrorsControllerさまざまなHTTPエラーを処理するwithアクションを定義します。

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        return Content("General failure", "text/plain");
    }

    public ActionResult Http404()
    {
        return Content("Not found", "text/plain");
    }

    public ActionResult Http403()
    {
        return Content("Forbidden", "text/plain");
    }
}

次に、Application_Errorin にサブスクライブして、Global.asaxこのコントローラーを呼び出します。

protected void Application_Error()
{
    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    Response.Clear();
    Server.ClearError();
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;
    if (httpException != null)
    {
        Response.StatusCode = httpException.GetHttpCode();
        switch (Response.StatusCode)
        {
            case 403:
                routeData.Values["action"] = "Http403";
                break;
            case 404:
                routeData.Values["action"] = "Http404";
                break;
        }
    }

    IController errorsController = new ErrorsController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
}

4
ほんの少しのメモ。各ActionResultでそれぞれのケース(404、500など)でビューをレンダリングしたかったので、ビューを返しました。しかし、私はApplication_Errorのコンテンツを回避しようとしました。失敗した場合は、静的なHTMLページが返されます。(誰かが望むなら私はコードを投稿することができます)
John Louros

4
MVC3でこのソリューションを使用してレンダリングするかみそりビューを取得できません。たとえば、View(model)を返すと、空白の画面しか表示されません。
Extrakunは、2011年

2
統合されたIIS7用に修正するために、TrySkipIisCustomErrorsを追加しました。stackoverflow.com/questions/1706934/…を
Pavel Savara

1
@ajbeaven Executeは、IControllerインターフェースで定義されたメソッドです。これはおそらく保護できません。コードをより注意深く見てください。メソッドを呼び出す変数IController errorsController = new ErrorsController();の型に注意してください。これはタイプであるため、このメソッドの呼び出しを妨げるものは絶対にありません。ちなみに、ControllerクラスとMVC 3で保護されていたため、この点に変更はありません。errorsControllerExecuteIControllerExecute
Darin Dimitrov

2
:明示的応答のコンテンツタイプを指定することにより、固定Response.ContentType = "text/html";
ajbeaven


6

これは、Web.Configファイルでも行うことができます。IIS 7.5で機能する例を次に示します。

     <system.webServer>
          <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
                <remove statusCode="502" subStatusCode="-1" />
                <remove statusCode="501" subStatusCode="-1" />
                <remove statusCode="412" subStatusCode="-1" />
                <remove statusCode="406" subStatusCode="-1" />
                <remove statusCode="405" subStatusCode="-1" />
                <remove statusCode="404" subStatusCode="-1" />
                <remove statusCode="403" subStatusCode="-1" />
                <remove statusCode="401" subStatusCode="-1" />
                <remove statusCode="500" subStatusCode="-1" />
                <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
                <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
                <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
                <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
                <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
                <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
                <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
                <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
                <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
           </httpErrors>
</system.webServer>

3

に設定値を追加し、エラー処理を実行するかどうかをEnableCustomErrorPage確認IsDebuggingEnabledしています。

<customErrors/>ASP.NETには既に構成が存在するため(これはまさにこの目的のためのものです)、次のように言うのが最も簡単です。

    protected void Application_Error()
    {
        if (HttpContext.Current == null) 
        {
                // errors in Application_Start will end up here                
        }
        else if (HttpContext.Current.IsCustomErrorEnabled)
        {
                // custom exception handling
        }
    }

次に、その<customErrors mode="RemoteOnly" />ようにデプロイしても安全な設定を配置します。カスタムエラーページをテストする必要がある場合は、設定して<customErrors mode="On" />、動作することを確認できます。

アクティブなコンテキストはありませんが、HttpContext.Current例外はApplication_Startこのthisメソッドであるため、null かどうかを確認する必要もあります。


2

Jeff Atwoodのユーザーフレンドリーな例外処理モジュールを実装して、httpステータスコードを少し変更するだけで、ユーザーフレンドリーなエラーページを正しいhttpステータスコードで表示できます。リダイレクトなしで動作します。コードは2004(!)のものですが、MVCでうまく機能します。MVCプロジェクトのソースコードをまったく変更することなく、web.configで完全に構成できます。

ステータスではなく元のHTTPステータスを返すために必要な変更200については、この関連フォーラムの投稿で説明されています。

基本的に、Handler.vbでは、次のようなものを追加できます。

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If

0

MVC 4.5を使用していますが、Darinのソリューションに問題がありました。注:Darinのソリューションは優れており、私はそれを使って自分のソリューションを考え出しました。これが私の修正したソリューションです:

protected void Application_Error(object sender, EventArgs e)
{           
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();

Response.Clear();
Server.ClearError();


if (httpException != null)
{
    var httpContext = HttpContext.Current;

    httpContext.RewritePath("/Errors/InternalError", false);

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.Server.TransferRequest("/Errors/Http403", true);
                break;
            case 404:
                httpContext.Server.TransferRequest("/Errors/Http404", true);
                break;
            default:
                httpContext.Server.TransferRequest("/Errors/InternalError", true);
                break;
        }
    }
    else
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.RewritePath(string.Format("/Errors/Http403", true));
                break;
            case 404:
                httpContext.RewritePath(string.Format("/Errors/Http404", true));
                break;
            default:
                httpContext.RewritePath(string.Format("/Errors/InternalError", true));
                break;
        }

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }
}
}

2
Darinのソリューションにはどのような問題がありましたか?
ケニーエビット2014年

競合する回答を促した経験した問題については説明しませんでした。
ivanjonas 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.