web-dev-qa-db-ja.com

ASP.NET MVC 404エラー処理

可能性のある複製:
ASP.NET MVCで404を適切に処理するにはどうすればよいですか?

Asp.Net MVC(RC 5)の404 Httpエラーハンドラー で説明されている変更を加えましたが、まだ標準の404エラーページが表示されています。 IISで何かを変更する必要がありますか?

129
Clearly

さらに別のソリューション。

ErrorControllersまたは静的ページを404エラー情報とともに追加します。

Web.configを変更します(コントローラーの場合)。

<system.web>
    <customErrors mode="On" >
       <error statusCode="404" redirect="~/Errors/Error404" />
    </customErrors>
</system.web>

または静的ページの場合

<system.web>
    <customErrors mode="On" >
        <error statusCode="404" redirect="~/Static404.html" />
    </customErrors>
</system.web>

これは、逃したルートと逃したアクションの両方を処理します。

142
Mike Chaliy

MVC(特にMVC3)で404を適切に管理する方法についてA LOTを調査しました。これ、私見は私が思いついた最高のソリューションです:

Global.asaxの場合:

public class MvcApplication : HttpApplication
{
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }
}

ErrorsController:

public sealed class ErrorsController : Controller
{
    public ActionResult NotFound()
    {
        ActionResult result;

        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest())
            result = View(model);
        else
            result = PartialView("_NotFound", model);

        return result;
    }
}

編集:

IoC(例:AutoFac)を使用している場合は、次を使用してコントローラーを作成する必要があります:

var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);

の代わりに

IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));

(オプション)

説明:

ASP.NET MVC3アプリが404を生成できる場所について考えることができる6つのシナリオがあります。

ASP.NETにより生成:

  • シナリオ1:URLはルートテーブルのルートと一致しません。

ASP.NET MVCにより生成:

  • シナリオ2:URLはルートに一致しますが、存在しないコントローラーを指定します。

  • シナリオ3:URLはルートに一致しますが、存在しないアクションを指定します。

手動生成:

  • シナリオ4:アクションは、メソッドHttpNotFound()を使用してHttpNotFoundResultを返します。

  • シナリオ5:アクションは、ステータスコード404でHttpExceptionをスローします。

  • シナリオ6:アクションは、Response.StatusCodeプロパティを手動で404に変更します。

目的

  • (A)カスタム404エラーページをユーザーに表示します。

  • (B)クライアント応答の404ステータスコードを維持します(特にSEOにとって重要)。

  • (C)302リダイレクトを伴うことなく、応答を直接送信します。

ソリューションの試行:カスタムエラー

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

このソリューションの問題:

  • シナリオ(1)、(4)、(6)の目的(A)に準拠していない。
  • 目的(B)に自動的に準拠しません。手動でプログラムする必要があります。
  • 目標に準拠していません(C)。

ソリューションの試み:HTTPエラー

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

このソリューションの問題:

  • IIS 7+でのみ機能します。
  • シナリオ(2)、(3)、(5)の目的(A)に準拠していない。
  • 目的(B)に自動的に準拠しません。手動でプログラムする必要があります。

ソリューションの試み:ReplaceによるHTTPエラー

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

このソリューションの問題:

  • IIS 7+でのみ機能します。
  • 目的(B)に自動的に準拠しません。手動でプログラムする必要があります。
  • アプリケーションレベルのhttp例外を覆い隠します。例えば。 customErrorsセクションやSystem.Web.Mvc.HandleErrorAttributeなどは使用できません。一般的なエラーページのみを表示することはできません。

カスタムエラーとHTTPエラーの試行

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

そして

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

このソリューションの問題:

  • IIS 7+でのみ機能します。
  • 目的(B)に自動的に準拠しません。手動でプログラムする必要があります。
  • シナリオ(2)、(3)、(5)の目的(C)に準拠していません。

独自のライブラリを作成しようとさえする前にこれで問題を抱えている人々( http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.htmlを参照 )。しかし、以前のソリューションは、外部ライブラリを使用する複雑さなしにすべてのシナリオをカバーするようです。

360
Marco

マルコからの回答が最高のソリューションです。私は自分のエラー処理を制御する必要があり、本当にそれを制御することを意味します。もちろん、ソリューションを少し拡張し、すべてを管理する完全なエラー管理システムを作成しました。このソリューションについては他のブログでも読んでおり、ほとんどの上級開発者に受け入れられているようです。

私が使用している最終的なコードは次のとおりです。

protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            var exception = Server.GetLastError();
            var httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values["controller"] = "ErrorManager";
            routeData.Values["action"] = "Fire404Error";
            routeData.Values["exception"] = exception;
            Response.StatusCode = 500;

            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (Response.StatusCode)
                {
                    case 404:
                        routeData.Values["action"] = "Fire404Error";
                        break;
                }
            }
            // Avoid IIS7 getting in the middle
            Response.TrySkipIisCustomErrors = true;
            IController errormanagerController = new ErrorManagerController();
            HttpContextWrapper wrapper = new HttpContextWrapper(Context);
            var rc = new RequestContext(wrapper, routeData);
            errormanagerController.Execute(rc);
        }
    }

そして、私のErrorManagerController内:

        public void Fire404Error(HttpException exception)
    {
        //you can place any other error handling code here
        throw new PageNotFoundException("page or resource");
    }

今、私のアクションで、作成したカスタム例外をスローしています。そして、コントローラーは、作成したカスタムのコントローラーベースのクラスから継承しています。カスタムベースコントローラーは、エラー処理をオーバーライドするために作成されました。カスタムベースコントローラークラスは次のとおりです。

public class MyBasePageController : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
        filterContext.GetType();
        filterContext.ExceptionHandled = true;
        this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
        base.OnException(filterContext);
    }
}

上記のコードの「ErrorManager」は、ExceptionContextに基づくモデルを使用しているビューです

私のソリューションは完璧に機能し、ウェブサイトでエラーを処理し、例外の種類に応じてさまざまなメッセージを表示できます。

5
Yousi

これはすべてをキャッチするための最良の方法のようです。

ASP.NET MVCで404を適切に処理するにはどうすればよいですか?

4
Clearly

IISでは、エラーコードに基づいて「特定の」ページへのリダイレクトを指定できます。例では、404を構成できます->カスタマイズされた404エラーページ。

1
J.W.

推奨できるのは、FilterAttributeを調べることです。たとえば、MVCにはすでにHandleErrorAttributeがあります。 404のみを処理するようにカスタマイズできます。興味がある場合は、例を見てみましょう。

ところで

前の質問で受け入れた解決策(最後のルートを使用)は、ほとんどの状況で機能しません。 HandleUnknownActionを使用した2番目のソリューションは機能しますが、各コントローラーでこの変更を行うか、単一のベースコントローラーを使用する必要があります。

私の選択は、HandleUnknownActionを使用したソリューションです。

1
Mike Chaliy