web-dev-qa-db-ja.com

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

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

そのため、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");
    }
}
}
144
John Louros

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

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_ErrorGlobal.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);
}
201
Darin Dimitrov

MVCでカスタムエラーページを作成する方法 http://kitsula.com/Article/MVC-Custom-Error-Pages の記事があります。

18
Shaman

これは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>
6
Brett Allred

EnableCustomErrorPageの設定値を追加したことと、IsDebuggingEnabledをチェックして、エラー処理を実行するかどうかを判断していることがわかります。

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

    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がnullであるかどうかも確認する必要があります。

3
Simon_Weaver

Jeff Atwoodの ser Friendly Exception Handling module をhttpステータスコードにわずかな変更を加えて実装することにより、正しいhttpステータスコードでユーザーフレンドリーなエラーページを表示できます。リダイレクトなしで機能します。コードは2004年(!)のものですが、MVCでうまく機能します。 web.configで完全に構成でき、MVCプロジェクトのソースコードはまったく変更されません。

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

基本的に、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
2
Martin_ATS

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);
    }
}
}
0
MVCdragon