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


432

RC2を使用しています

URLルーティングの使用:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

上記は次のようなリクエストを処理するようです(最初のMVCプロジェクトによってデフォルトのルートテーブルがセットアップされていると想定): "/ blah / blah / blah / blah"

コントローラー自体のHandleUnknownAction()をオーバーライドします。

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

ただし、以前の戦略では、Bad / Unknownコントローラへのリクエストは処理されません。たとえば、「/ IDoNotExist」がないので、これをリクエストすると、ルーティング+オーバーライドを使用する場合、404ではなく、一般的な404ページがWebサーバーから取得されます。

最後に、私の質問は: MVCフレームワーク自体でルートまたは何か他のものを使用してこのタイプのリクエストをキャッチする方法はありますか?

または、デフォルトで404ハンドラーとしてWeb.Config customErrorsを使用し、これをすべて無視する必要がありますか?customErrorsを使用する場合、直接アクセスに関するWeb.Configの制限により、/ Viewsの外に汎用404ページを保存する必要があると思います。


3
それは404エラーです、私はそれについて気にしません。間違いなくユーザーが何かをタイプミスしたので、404を表示させます。または、それが移動するものである場合、アプリケーションはその要求を受け取り、永続的にリダイレクトする必要があります。404はアプリケーションではなくウェブサーバーに属しています。エラーのあるiisページはいつでもカスタマイズできます。
mamu 2010

あなたはこのソリューションと同様にblog.dantup.com/2009/04/…を
開発者

ben.onfabrik.com/posts/aspnet-mvc-custom-error-pagesにもいくつかの良い情報があります
Chris S

4
4つの安定したリリースが5年以上後にリリースされたのは残念です。asp.netMVC + IISで404を処理する状況は実際には改善されておらず、これを処理する方法についてのQ&Aがまだあります。
joelmdev 14

回答:


271

コードはhttp://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspxから取得して機能しますASP.net MVC 1.0でも

ここに私がhttp例外を処理する方法があります:

protected void Application_Error(object sender, EventArgs e)
{
   Exception exception = Server.GetLastError();
   // Log the exception.

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

   RouteData routeData = new RouteData();
   routeData.Values.Add("controller", "Error");

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}

23
更新:http 404を確認することは間違いなく必要ですが、500を取得するタイミングがよくわかりません。また、Response.StatusCode = 404または500を明示的に設定する必要があります。そうしないと、Googleがこれらのページのインデックス作成を開始しますこのコードが現在行う200ステータスコードを返す場合
Simon_Weaver

6
@Simon_Weaver:同意した!これは404ステータスコードを返す必要があります。それができるまで、それは本質的に404ソリューションとして壊れています。:このチェックcodinghorror.com/blog/2007/03/...
マットKocaj

1
この全体的な提案には根本的な欠陥があります-実行がGlobal.asaxにバブリングするまでに、HttpContextの多くが欠落しています。例が示すように、コントローラーにルーティングすることはできません。上部のブログリンクのコメントを参照してください。
Matt Kocaj、

3
上記のコメントの一部とリンクされた投稿が言及しているように、これは機能していないようです。エラーコントローラーがヒットしましたが、空白の画面に戻ります。(mvc 3を使用)
RyanW 2011年

4
何かがおかしいと感じた場合、MVCの目的はすべて、その抽象化をすべて削除することですが、それでもここに戻ります...
Alex Nolasco、2011

255

404の要件

以下は404ソリューションの要件であり、以下にそれを実装する方法を示します。

  • 一致しないルートを不適切なアクションで処理したい
  • 一致しないルートを不良コントローラで処理したい
  • 一致しないルート(アプリが理解できない任意のURL)を処理したいのですが、Global.asaxまたはIISにバブリングしたくないので、MVCアプリに適切にリダイレクトできません。
  • 上記と同じ方法でカスタム404を処理する方法が必要です-存在しない(おそらく削除されている)オブジェクトのIDが送信されたときのように
  • 私は私が後で(必要に応じて、より多くのデータを送り出すことができたとMVCのビュー(ない静的ページ)を返すようにすべての私の404エラーをしたいの良い404点のデザインをし、彼らがしなければならない HTTPステータスコード404を返します

解決

Application_Error未処理の例外やロギング(Shay Jacobyの回答が示すように)などのより高度なものについてはGlobal.asaxに保存する必要がありますが、404処理は保存しないでください。これが、私の提案が404のものをGlobal.asaxファイルから除外する理由です。

ステップ1:404エラーロジックの共通の場所を用意する

これは保守性のために良い考えです。ErrorControllerを使用して、うまく設計された404ページに対する将来の改善が容易に適応できるようにします。また、応答に404コードが含まれていることを確認してください

public class ErrorController : MyController
{
    #region Http404

    public ActionResult Http404(string url)
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        var model = new NotFoundViewModel();
        // If the url is relative ('NotFound' route) then replace with Requested path
        model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
            Request.Url.OriginalString : url;
        // Dont get the user stuck in a 'retry loop' by
        // allowing the Referrer to be the same as the Request
        model.ReferrerUrl = Request.UrlReferrer != null &&
            Request.UrlReferrer.OriginalString != model.RequestedUrl ?
            Request.UrlReferrer.OriginalString : null;

        // TODO: insert ILogger here

        return View("NotFound", model);
    }
    public class NotFoundViewModel
    {
        public string RequestedUrl { get; set; }
        public string ReferrerUrl { get; set; }
    }

    #endregion
}

ステップ2:カスタムの404アクションを簡単に呼び出してワイヤーアップできるように、基本コントローラークラスを使用する HandleUnknownAction

ASP.NET MVCの404は、さまざまな場所で捕捉する必要があります。最初はHandleUnknownActionです。

InvokeHttp404この方法は、への再ルーティングのための共通の場所を作成ErrorControllerし、私たちの新しいHttp404アクションを。DRYだと思います!

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

ステップ3:コントローラーファクトリで依存性注入を使用し、404 HttpExceptionsを接続する

そうです(StructureMapである必要はありません):

MVC1.0の例:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

MVC2.0の例:

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == 404)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }

エラーの発生源に近い場所でエラーをキャッチする方が良いと思います。これが、Application_Errorハンドラーよりも上記を好む理由です。

これは、404をキャッチする2番目の場所です。

ステップ4:アプリへの解析に失敗したURLのNotFoundルートをGlobal.asaxに追加する

このルートは私たちのHttp404行動を指し示す必要があります。urlルーティングエンジンがここでドメイン部分を削除しているため、パラメーターは相対URLになることに注意してください。そのため、ステップ1で条件付きURLロジックをすべて用意しています。

        routes.MapRoute("NotFound", "{*url}", 
            new { controller = "Error", action = "Http404" });

これは、自分で呼び出さないMVCアプリで404をキャッチする最後の3番目の場所です。ここで一致しないルートをキャッチしない場合、MVCは問題をASP.NET(Global.asax)に渡すため、この状況ではそれを望んでいません。

ステップ5:最後に、アプリが何かを見つけられないときに404を呼び出します

不正なIDがローンコントローラーに送信されたときのように(から派生MyController):

    //
    // GET: /Detail/ID

    public ActionResult Detail(int ID)
    {
        Loan loan = this._svc.GetLoans().WithID(ID);
        if (loan == null)
            return this.InvokeHttp404(HttpContext);
        else
            return View(loan);
    }

これをすべて、より少ないコードでより少ない場所に接続できればいいのですが、このソリューションは保守性が高く、テストしやすく、かなり実用的だと思います。

これまでのフィードバックに感謝します。もっと手に入れたいです。

注:これは私の元の回答から大幅に編集されていますが、目的/要件は同じです-これが新しい回答を追加していない理由です


12
完全な書き込みをありがとう。追加の1つは、IIS7で実行するときに、プロパティ「TrySkipIisCustomErrors」をtrueに設定して追加する必要があることです。それ以外の場合、IISはデフォルトの404ページを返します。Response.TrySkipIiisCustomErrors = trueを追加しました。ステータスコードを設定するステップ5の行の後。 msdn.microsoft.com/en-us/library/...
リック・

1
@Ryan customErrorsweb.config のセクションは、IISでない場合でもaspnetで高レベルで処理される静的リダイレクトページを定義します。結果をMVCビューにする必要があるため、これは私が望んでいたものではありません(したがって、データをビューに含めることができます)。私はcustomErrors断固として「MVCでは廃止された」とは言いませんが、私とこの404ソリューションでは確かにそうです。
Matt Kocaj、2011年

1
また、誰かがステップ3を更新して、StructureMapを使用しないようにすることはできますか?たぶん、ControllerFactoryをまだ使用していない場合は、簡単に実装できる汎用のControllerFactoryだけかもしれません。
デビッドマードック

7
これはMVC3で正常に動作します。代わりObjectFactory.GetInstanceにMVC3 に切り替えたDependencyResolver.Current.GetServiceので、より汎用的です。私はNinjectを使用しています。
kamranicus

122
他の誰かが、Webフレームワークの404のような一般的なものは非常に複雑で複雑であることを明らかに気違いと感じていますか?
クエンティン・スターリン

235

ASP.NET MVCはカスタム404ページをあまりサポートしていません。カスタムコントローラーファクトリ、キャッチオールルート、ベースコントローラークラスHandleUnknownAction-argh!

これまでのところ、IISカスタムエラーページの方が優れています。

web.config

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

ErrorController

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

サンプルプロジェクト


38
これは受け入れられた答えであるはずです!!! IIS Expressを使用したASP.NET MVC 3で問題なく動作します。
AndreiRînea

7
IIS7 +を使用している場合、これは間違いなく進むべき道です。+1!
elo80ka

3
同じプロジェクト内のJSONで作業しているときにステータス404のみを返すことは可能ですか?
VinnyG 2011

6
これはiis Expressでうまく機能していますが、サイトを運用環境のIIS 7.5に展開するとすぐに、エラービューではなくホワイトページが表示されます。
Moulde 2012年

2
私のテスト(MVC3を使用)によると、これは機能customErrors mode="On"するHandleErrorAttributeために壊れます。コントローラーアクションの未処理の例外のカスタムエラーページは提供されなくなりました。
スラウマ

153

クイックアンサー/ TL; DR

ここに画像の説明を入力してください

怠惰な人々のために:

Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

次に、この行を削除します global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

そして、これはIIS7 +とIIS Express専用です。

カッシーニを使用している場合..まあ..ええと..厄介です... ぎこちない


長い、説明された答え

私はこれが答えられたことを知っています。しかし、答えは本当に簡単です(これに本当に答えてくれたDavid FowlerDamian Edwardsに乾杯)。

カスタムを行う必要はありません

の場合ASP.NET MVC3、すべての部分が存在します。

ステップ1-> 2つのスポットでweb.configを更新します。

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

そして

<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
    </httpErrors>    

...
<system.webServer>
...
</system.web>

次に、使用することにしたルートを注意深くメモします。何でも使えますが、私のルートは

  • /NotFound <-404が見つからない、エラーページの場合。
  • /ServerError<-その他のエラーの場合、コードで発生するエラーを含めます。これは500内部サーバーエラーです

の最初のセクションにカスタムエントリ<system.web>1つしかない方法をご覧ください。statusCode="404"エントリー?他のすべてのエラー500 Server Error(コードにバグがあり、ユーザーのリクエストがクラッシュしたときに発生する厄介なエラーなど)を除いて、ステータスコードは1つしか記載していません。その他のエラーはすべて、設定によって処理されますdefaultRedirect="/ServerError"。 、404ページが見つからない場合は、ルートに移動してください/ServerError

OK。それは邪魔にならない..今リストされている私のルートにglobal.asax

手順2-Global.asaxでルートを作成する

これが私の完全なルートセクションです。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});

    routes.MapRoute(
        "Error - 404",
        "NotFound",
        new { controller = "Error", action = "NotFound" }
        );

    routes.MapRoute(
        "Error - 500",
        "ServerError",
        new { controller = "Error", action = "ServerError"}
        );

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
        );
}

これには2つの無視ルート-> axd'sfavicons(ooo!ボーナス無視ルート、あなたのために!)がリストされています(そして、順序はここで命令です)。この場合、デフォルトです。もちろん、他にもありますが、それは私のWebサイトにとって特別なことです。エラールートがリストの一番上にあることを確認してください。順序は必須です。

最後に、global.asaxファイル内にいる間は、HandleError属性をグローバルに登録しません。いやいやいやいや ナッダ。いいえ。ニエン。負。いやいやいやいや…

この行を削除 global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

手順3-アクションメソッドを使用してコントローラーを作成する

次に、2つのアクションメソッドを持つコントローラを追加します...

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ActionResult ServerError()
    {
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // Todo: Pass the exception into the view model, which you can make.
        //       That's an exercise, dear reader, for -you-.
        //       In case u want to pass it to the view, if you're admin, etc.
        // if (User.IsAdmin) // <-- I just made that up :) U get the idea...
        // {
        //     var exception = Server.GetLastError();
        //     // etc..
        // }

        return View();
    }

    // Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
    public ActionResult ThrowError()
    {
        throw new NotImplementedException("Pew ^ Pew");
    }
}

さて、これをチェックしてみましょう。まず、ここに属性はありません [HandleError]。どうして?組み込みのASP.NETフレームワークはすでにエラーを処理しており、エラーを処理するために必要なすべてのたわごとを指定しているためです:)これはこのメソッドにあります!

次に、2つのアクションメソッドがあります。難しいことはありません。例外情報を表示したい場合は、Server.GetLastError()その情報を取得するために使用できます。

ボーナスWTF:はい、エラー処理をテストするために3つ目のアクションメソッドを作成しました。

ステップ4-ビューを作成する

最後に、2つのビューを作成します。このコントローラの場合、emを通常のビュースポットに配置します。

ここに画像の説明を入力してください

ボーナスコメント

  • あなたは必要ありません Application_Error(object sender, EventArgs e)
  • 上記の手順はすべてElmahで完全に機能します。Elmah fraking wroxs!

そして、それは、私の友だちです。

これで、これを読んでユニコーンが賞品になりました!

ここに画像の説明を入力してください


だから私はこれを実装しようとしましたが、いくつかの問題...最初に、weeb.configのパスの前に〜が必要であるか、仮想ディレクトリでは機能しません。2-IISカスタムエラーが発生し、ビューがまったくレンダリングしないレイアウトを使用している場合は、白いページだけです。この行をコントローラー「Response.TrySkipIisCustomErrors = true;」に追加することで解決しました。。ただし、ファイルであるが、mysite / whatever / fake.htmlのような404 .. が白いページを取得するURLにアクセスした場合でも機能しません。
Robert Noack 14年

3
-1、申し訳ありませんが、私にとって404のURLを変更するソリューションはすべて間違っています。webconfigでは、MVCでurlを変更せずに処理できる方法はありません。または、静的htmlファイルまたはaspx(そう、プレーンな古いaspxファイル)を作成して、それを実行できるようにする必要があります。あなた?aspxerrorpath=/er/not/foundがURLを持ちたいならあなたの解決策は素晴らしいです。
Gutek、2014

7
これは本当に奇妙に聞こえるかもしれませんが、私の回答は何年も前に提供されたものであり、私はあなたの@Gutekに同意します。エラーページへのリダイレクトを行うのはもう好きではありませ。私は以前使用しました(私の回答を参照:P)。エラーが/ some / resource ..で発生した場合、そのリソースは404や500などを返す必要があります。それ以外の場合は、MASIVE SEOの影響があります。ああ..時間がどのように変化するか:)
Pure.Krome

@Gutek customErrors redirectMode = "ResponseRewrite"を知っていますか?そして、404を返すことはセキュリティの観点から理想的ではありません
Jowen

1
@Chris <お気に入りの神をここに挿入>いまいましい。今何だったか思い出せない。さて、救助への私のミームのコレクション...そして..修正されました。
Pure.Krome 2016年

86

私が検討してきたA LOTを正しくMVCで404エラーを管理する方法で(特にMVC3) 、これは、私見では、私が作ってみた最適なソリューションです。

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;
    }
}

(オプション)

説明:

私の知る限り、ASP.NET MVC3アプリが404を生成できるケースは6つあります。

(ASP.NET Frameworkによって自動的に生成されます:)

(1) URLがルートテーブルで一致するものを見つけられない。

(ASP.NET MVCフレームワークによって自動的に生成されます:)

(2) URLがルートテーブルで一致を検出しましたが、存在しないコントローラーを指定しています。

(3) URLがルートテーブルで一致を検出しましたが、存在しないアクションを指定しています。

(手動で生成:)

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

(5)アクションは、ステータスコード404のHttpExceptionをスローします。

(6)アクションは手動でResponse.StatusCodeプロパティを404に変更します。

通常、3つの目的を達成する必要があります。

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

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

(3) 302リダイレクトを行わずに、直接応答を送信します。

これを達成するためのさまざまな方法があります。

(1)

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

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

  1. ケース(1)、(4)、(6)の目的(1)に準拠していない。
  2. 目的(2)に自動的に準拠しない。手動でプログラムする必要があります。
  3. 目的(3)に準拠していない。

(2)

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

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

  1. IIS 7以降でのみ機能します。
  2. ケース(2)、(3)、(5)の目的(1)に準拠していない。
  3. 目的(2)に自動的に準拠しない。手動でプログラムする必要があります。

(3)

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

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

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

(4)

<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>

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

  1. IIS 7以降でのみ機能します。
  2. 目的(2)に自動的に準拠しない。手動でプログラムする必要があります。
  3. ケース(2)、(3)、(5)の目的(3)に準拠していない。

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


すばらしい答えです。より多くの賛成投票に値する。global.asaxコードがApplication_Errorで機能しない、または属していないのはなぜですか。
NinjaNye 2012

7
ありがとう!コントローラーからスローされた明示的な404はASP.NETではエラーと見なされないため、Application_Errorの下では実行できません。コントローラーからHttpNotFound()を返す場合、Application_Errorイベントはトリガーされません。
マルコ

1
public ActionResult NotFound() {}ErrorsController を忘れたようです。また、_NotFoundAJAXリクエストでパーシャルがどのように見えるかを説明できますか?
d4n3

2
MVC 4で、私は常に取得MissingMethodException: Cannot create an abstract classライン上c.Execute(new RequestContext(new HttpContextWrapper(Context), rd)); の任意のアイデア?
µBio

1
「見つからない」URLのパスにドットが含まれている場合(例:example.com/hi.bob)、Application_EndRequestがまったく起動せず、IEの汎用404ページが表示されます。
Bob.at.Indigo.Health 2014

13

私はcottsaksソリューションが本当に好きで、それは非常に明確に説明されていると思います。私の唯一の追加は次のようにステップ2を変更することでした

public abstract class MyController : Controller
{

    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        //if controller is ErrorController dont 'nest' exceptions
        if(this.GetType() != typeof(ErrorController))
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

基本的に、これは無効なアクションとコントローラーを含むURLが例外ルーチンを2回トリガーするのを停止します。たとえば、asdfsdf / dfgdfgdなどのURLの場合


4
これは素晴らしいです。それらの「2回」のケースは私を悩ませ始めていました。私の回答を更新
Matt Kocaj

ユーザーが間違ったコントローラーとアクション名を入力した場合、上記のソリューションはまったく機能しますか?
Monojit Sarkar 2018年

6

@cottsakのメソッドを無効なコントローラーに対して機能させる唯一の方法は、CustomControllerFactoryの既存のルートリクエストを変更することでした。

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType); 
            else
                return ObjectFactory.GetInstance(controllerType) as Controller;
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                requestContext.RouteData.Values["controller"] = "Error";
                requestContext.RouteData.Values["action"] = "Http404";
                requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);

                return ObjectFactory.GetInstance<ErrorController>();
            }
            else
                throw ex;
        }
    }
}

私はMVC 2.0を使用していることを述べておきます。


なぜなのかご存知ですか?(MVC2固有?)
Matt Kocaj 2010年

重要なのは、新しいリクエストを作成するのではなく、既存のリクエストを変更することだったと思いますが、少し前にこれを行ったので、それが確かでした。「InvokeHttp404」はコントローラーファクトリーでは機能しませんでした。
Dave K

今日は私の回答をいくつかのMVC2の詳細で更新しました。上記の私の解決策がまだ機能しない場合は教えてください。
Matt Kocaj、2011

4

これは、不正なコントローラ名、不正なルート名、およびアクションメソッド内に適合すると思われるその他の基準へのリクエストを処理できるMVCツールを使用した別のメソッドです。個人的には、302/200リダイレクトを実行Server.Transferし、Razorビューを使用したResponseRewrite()をサポートしないため、できるだけ多くのweb.config設定を回避することを好みます。SEOの理由から、カスタムエラーページを含む404を返したいと思います。

これの一部は、上記のcottsakの手法の新しい見方です。

このソリューションでは、代わりにMVC 3エラーフィルターを優先する最小限のweb.config設定も使用します。

使用法

アクションまたはカスタムActionFilterAttributeからHttpExceptionをスローするだけです。

Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")

ステップ1

次の設定をweb.configに追加します。これは、MVCのHandleErrorAttributeを使用するために必要です。

<customErrors mode="On" redirectMode="ResponseRedirect" />

ステップ2

HTTPエラーを除いて、MVCフレームワークのHandleErrorAttributeと同様のカスタムHandleHttpErrorAttributeを追加します。

<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
    Inherits FilterAttribute
    Implements IExceptionFilter

    Private Const m_DefaultViewFormat As String = "ErrorHttp{0}"

    Private m_HttpCode As HttpStatusCode
    Private m_Master As String
    Private m_View As String

    Public Property HttpCode As HttpStatusCode
        Get
            If m_HttpCode = 0 Then
                Return HttpStatusCode.NotFound
            End If
            Return m_HttpCode
        End Get
        Set(value As HttpStatusCode)
            m_HttpCode = value
        End Set
    End Property

    Public Property Master As String
        Get
            Return If(m_Master, String.Empty)
        End Get
        Set(value As String)
            m_Master = value
        End Set
    End Property

    Public Property View As String
        Get
            If String.IsNullOrEmpty(m_View) Then
                Return String.Format(m_DefaultViewFormat, Me.HttpCode)
            End If
            Return m_View
        End Get
        Set(value As String)
            m_View = value
        End Set
    End Property

    Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
        If filterContext Is Nothing Then Throw New ArgumentException("filterContext")

        If filterContext.IsChildAction Then
            Return
        End If

        If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
            Return
        End If

        Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
        If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
            Return
        End If

        If ex.GetHttpCode <> Me.HttpCode Then
            Return
        End If

        Dim controllerName As String = filterContext.RouteData.Values("controller")
        Dim actionName As String = filterContext.RouteData.Values("action")
        Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)

        filterContext.Result = New ViewResult With {
            .ViewName = Me.View,
            .MasterName = Me.Master,
            .ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
            .TempData = filterContext.Controller.TempData
        }
        filterContext.ExceptionHandled = True
        filterContext.HttpContext.Response.Clear()
        filterContext.HttpContext.Response.StatusCode = Me.HttpCode
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
    End Sub
End Class

ステップ3

のGlobalFilterCollection(GlobalFilters.Filters)にフィルタを追加しGlobal.asaxます。この例では、すべてのInternalServerError(500)エラーをError共有ビュー(Views/Shared/Error.vbhtml)にルーティングします。NotFound(404)エラーは、共有ビューのErrorHttp404.vbhtmlにも送信されます。ここに401エラーを追加して、これを追加のHTTPエラーコードに拡張する方法を示します。これらは共有ビューでなければならず、すべてSystem.Web.Mvc.HandleErrorInfoオブジェクトをモデルとして使用することに注意してください。

filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp401", .HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp404", .HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View = "Error"})

ステップ4

基本コントローラークラスを作成し、それをコントローラーで継承します。この手順により、不明なアクション名を処理し、HTTP 404エラーをHandleHttpErrorAttributeに発生させることができます。

Public Class BaseController
    Inherits System.Web.Mvc.Controller

    Protected Overrides Sub HandleUnknownAction(actionName As String)
        Me.ActionInvoker.InvokeAction(Me.ControllerContext, "Unknown")
    End Sub

    Public Function Unknown() As ActionResult
        Throw New HttpException(HttpStatusCode.NotFound, "The specified controller or action does not exist.")
        Return New EmptyResult
    End Function
End Class

手順5

ControllerFactoryオーバーライドを作成し、Application_StartのGlobal.asaxファイルでオーバーライドします。この手順により、無効なコントローラー名が指定された場合にHTTP 404例外を発生させることができます。

Public Class MyControllerFactory
    Inherits DefaultControllerFactory

    Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
        Try
            Return MyBase.GetControllerInstance(requestContext, controllerType)
        Catch ex As HttpException
            Return DependencyResolver.Current.GetService(Of BaseController)()
        End Try
    End Function
End Class

'In Global.asax.vb Application_Start:

controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)

手順6

BaseController UnknownアクションのRoutTable.Routesに特別なルートを含めます。これは、ユーザーが不明なコントローラーや不明なアクションにアクセスした場合に404​​を発生させるのに役立ちます。

'BaseController
routes.MapRoute( _
    "Unknown", "BaseController/{action}/{id}", _
    New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)

概要

この例では、MVCフレームワークを使用して、フィルター属性と共有エラービューを使用したリダイレクトを行わずに404 Httpエラーコードをブラウザーに返す方法を示しました。また、無効なコントローラー名とアクション名が指定されたときに同じカスタムエラーページを表示する方法も示しています。

無効なコントローラー名、アクション名、およびHome / TriggerNotFoundアクションから生成されたカスタム404のスクリーンショットを追加します。このソリューションを使用して次のURLにアクセスすると、Fiddlerが404メッセージを返します。

/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound

上記のcottsakの投稿とこれらの記事は良い参考文献でした。


うーん、私はこれを機能させることができませんでした:The IControllerFactory 'aaa.bbb.CustomControllerFactory' did not return a controller for the name '123'.-なぜ私はそれを得るのでしょうか?
enashnash 2012

redirectMode = "ResponseRedirect"。これは302 Found + 200 OKを返しますが、これはSEOには適していません。
PussInBoots 2014年

4

未処理の領域、コントローラー、アクションで機能する私の短縮されたソリューション:

  1. ビュー404.cshtmlを作成します。

  2. コントローラーの基本クラスを作成します。

    public class Controller : System.Web.Mvc.Controller
    {
        protected override void HandleUnknownAction(string actionName)
        {
            Http404().ExecuteResult(ControllerContext);
        }
    
        protected virtual ViewResult Http404()
        {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return View("404");
        }
    }
  3. フォールバックとしてベースコントローラーを返すカスタムコントローラーファクトリを作成します。

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
  4. Application_Start()次の行に追加します。

    ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

3

MVC4では、WebAPI 404は次のように処理できます。

コースAPIコントローラー

    // GET /api/courses/5
    public HttpResponseMessage<Courses> Get(int id)
    {
        HttpResponseMessage<Courses> resp = null;

        var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();

        resp = aCourse == null ? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);

        return resp;
    }

ホームコントローラー

public ActionResult Course(int id)
{
    return View(id);
}

見る

<div id="course"></div>
<script type="text/javascript">
    var id = @Model;
    var course = $('#course');
    $.ajax({    
        url: '/api/courses/' + id,
        success: function (data) {
            course.text(data.Name);
        },
        statusCode: {
            404: function() 
            {
                course.text('Course not available!');    
            }
        }
    });
</script>

グローバル

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

結果

ここに画像の説明を入力してください


2

nugetでNotFoundMVCを試してください。動作しますが、セットアップはありません。


http://localhost/Views/Shared/NotFound.cshtmlカスタム404ページにはなりません。
Dan Friedman

カスタマイズは非常に簡単です。リクエストされたURLとリファラーにアクセスできるので、好きなことができます。私はこのパッケージを使用しており、非常にうまく機能しています。
Avrohom Yisroel

これは、非同期のTask <ActionResult>アクション(または他の同様のasync)アクションを使用しないという点で優れたパッケージです。MVC 5では、これは壊れたシナリオです。GitHubにはそれを回避するためのフォークがありますが、私にとってはそれはノーです。
Stargazer、2016年

2

誰かがそれを便利だと思った場合の私の解決策。

Web.configで:

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

Controllers/ErrorController.cs

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        if(Request.IsAjaxRequest()) {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Content("Not Found", "text/plain");
        }

        return View();
    }
}

追加PageNotFound.cshtmlShared、フォルダ、およびそれはそれです。


2
これは、302リダイレクトを発行し、次に200(OK)ステータスをクライアントに発行しませんか?彼らはまだ404ステータスになっているのではないでしょうか?
Sam

@Konamimanコード内の行を読み取るべきでmodel.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ? Request.Url.OriginalString : url;あり、model.RequestedUrl = Request.Url.OriginalString.Contains(url) && Request.Url.OriginalString != url ? Request.Url.OriginalString : url;(&&の代わりに&)はずではないですか?
ジャン=フランソワ・ビーチャム

2

ただし、標準CustomErrors構成は機能するはずですが、これに依存しServer.Transferているため、の内部実装はResponseRewriteMVCと互換性がありません。

これは私にとっては明らかな機能の穴のように感じられるので、HTTPモジュールを使用してこの機能を再実装することにしました。以下のソリューションでは、通常と同じように有効なMVCルートにリダイレクトすることで、HTTPステータスコード(404を含む)を処理できます。

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
    <error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>

これは、次のプラットフォームでテストされています。

  • 統合パイプラインモードのMVC4(IIS Express 8)
  • クラシックモードのMVC4(VS開発サーバー、Cassini)
  • クラシックモードのMVC4(IIS6)

利点

  • 任意のMVCプロジェクトにドロップできる汎用ソリューション
  • 従来のカスタムエラー構成のサポートを有効にします
  • 統合パイプラインモードとクラシックモードの両方で動作します

ソリューション

namespace Foo.Bar.Modules {

    /// <summary>
    /// Enables support for CustomErrors ResponseRewrite mode in MVC.
    /// </summary>
    public class ErrorHandler : IHttpModule {

        private HttpContext HttpContext { get { return HttpContext.Current; } }
        private CustomErrorsSection CustomErrors { get; set; }

        public void Init(HttpApplication application) {
            System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
            CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");

            application.EndRequest += Application_EndRequest;
        }

        protected void Application_EndRequest(object sender, EventArgs e) {

            // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
            if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {

                int statusCode = HttpContext.Response.StatusCode;

                // if this request has thrown an exception then find the real status code
                Exception exception = HttpContext.Error;
                if (exception != null) {
                    // set default error status code for application exceptions
                    statusCode = (int)HttpStatusCode.InternalServerError;
                }

                HttpException httpException = exception as HttpException;
                if (httpException != null) {
                    statusCode = httpException.GetHttpCode();
                }

                if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {

                    Dictionary<int, string> errorPaths = new Dictionary<int, string>();

                    foreach (CustomError error in CustomErrors.Errors) {
                        errorPaths.Add(error.StatusCode, error.Redirect);
                    }

                    // find a custom error path for this status code
                    if (errorPaths.Keys.Contains(statusCode)) {
                        string url = errorPaths[statusCode];

                        // avoid circular redirects
                        if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {

                            HttpContext.Response.Clear();
                            HttpContext.Response.TrySkipIisCustomErrors = true;

                            HttpContext.Server.ClearError();

                            // do the redirect here
                            if (HttpRuntime.UsingIntegratedPipeline) {
                                HttpContext.Server.TransferRequest(url, true);
                            }
                            else {
                                HttpContext.RewritePath(url, false);

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

                            // return the original status code to the client
                            // (this won't work in integrated pipleline mode)
                            HttpContext.Response.StatusCode = statusCode;

                        }
                    }

                }

            }

        }

        public void Dispose() {

        }


    }

}

使用法

これをweb.configの最後のHTTPモジュールとして含めます

  <system.web>
    <httpModules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </httpModules>
  </system.web>

  <!-- IIS7+ -->
  <system.webServer>
    <modules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </modules>
  </system.webServer>

注意を払っている人にとっては、統合パイプラインモードでは、Server.TransferRequest動作方法により、これが常にHTTP 200で応答することに気付くでしょう。適切なエラーコードを返すには、次のエラーコントローラーを使用します。

public class ErrorController : Controller {

    public ErrorController() { }

    public ActionResult Index(int id) {
        // pass real error code to client
        HttpContext.Response.StatusCode = id;
        HttpContext.Response.TrySkipIisCustomErrors = true;

        return View("Errors/" + id.ToString());
    }

}

2

ASP.NET MVCでのエラーの処理は、お尻の痛みです。私はこのページや他の質問やサイトでたくさんの提案を試みましたが、何もうまくいきません。1つの提案は、system.webserver内のweb.configのエラーを処理することでしたが、それは空白ページを返すだけでした。

このソリューションを思いついたときの私の目標は、

  • リダイレクトしない
  • デフォルトのエラー処理のように200 / Okではなく適切なステータスコードを返す

これが私の解決策です。

1 .Addに次のsystem.webのセクション

   <system.web>
     <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404"  redirect="~/Error/404.aspx" />
      <error statusCode="500" redirect="~/Error/500.aspx" />
     </customErrors>
    <system.web>

上記は、routes.configで処理されないすべてのURL と、特にビューで発生した未処理の例外を処理します。htmlではなくaspxを使用したことに注意してください。これは、コードビハインドに応答コードを追加できるようにするためです。

。プロジェクトのルートにError(または任意の名前)というフォルダーを作成し、2つのWebフォームを追加します。以下は私の404ページです。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title >Page Not found</title>
    <link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
    <div class="top-nav">
      <a runat="server" class="company-logo" href="~/"></a>
    </div>
    <div>
        <h1>404 - Page Not found</h1>
        <p>The page you are looking for cannot be found.</p>
        <hr />
        <footer></footer>
    </div>
</body>
</html>

そして、背後のコードに応答コードを設定しました

protected void Page_Load(object sender, EventArgs e)
{
    Response.StatusCode = 404;
}

500ページについても同じようにします

3。コントローラー内のエラーを処理します。それを行うには多くの方法があります。これは私のために働いたものです。すべての私のコントローラーは、ベースコントローラーを継承します。ベースコントローラーには、以下の方法があります

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Page not found....");
}

protected ActionResult ShowNotFound(string message)
{
    return ShowCustomError(HttpStatusCode.NotFound, message);
}

protected ActionResult ShowServerError()
{
    return ShowServerError("Application error....");
}

protected ActionResult ShowServerError(string message)
{
    return ShowCustomError(HttpStatusCode.InternalServerError, message);
}

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("You are not allowed ....");

}

protected ActionResult ShowNotAuthorized(string message)
{
    return ShowCustomError(HttpStatusCode.Forbidden, message);
}

protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
    Response.StatusCode = (int)statusCode;
    string title = "";
    switch (statusCode)
    {
        case HttpStatusCode.NotFound:
            title = "404 - Not found";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Access Denied";
            break;
        default:
            title = "500 - Application Error";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4 .CustomError.cshtmlを共有ビューフォルダに追加します。以下は私のものです。

<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>

これで、アプリケーションコントローラーで次のようなことができます。

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Try
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //or return ShowNotFound("Invalid widget!");
       return View(widget);
    }
    catch(Exception ex)
    {
       //log error
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

さて、警告のために。静的ファイルエラーは処理しません。したがって、example.com / widgetsなどのルートがあり、ユーザーがそれをexample.com/widgets.htmlに変更した場合、IISのデフォルトのエラーページが表示されるため、IISレベルのエラーを別の方法で処理する必要があります。


1

コメントが長すぎたので回答を投稿しています...

これは、ユニコーンの投稿/回答に対するコメントと質問の両方です。

https://stackoverflow.com/a/7499406/687549

私はこの答えを他よりも好んでいます。それは、その単純さと、Microsoftの一部の人々が明らかに相談を受けたという事実のためです。ただし、3つの質問があり、それらに回答できる場合は、ASP.NET MVC(x)アプリのインターウェブでのすべての404/500エラー回答の聖杯をこの回答と呼びます。

@ Pure.Krome

  1. GWBによって指摘されたコメントのSEO要素で回答を更新できますか(回答でこれについて言及したことはありませんでした)- <customErrors mode="On" redirectMode="ResponseRewrite"><httpErrors errorMode="Custom" existingResponse="Replace">

  2. ASP.NETチームの友達に、そのようにしても大丈夫かどうか尋ねてもらえますか-確認しておくといいでしょう-変更redirectModeしてexistingResponse、SEOで上手にプレイできるようにするための大きな問題ではないでしょうか。

  3. あなたはすべてのものを取り巻くいくつかの明確化を追加することができます(customErrors redirectMode="ResponseRewrite"customErrors redirectMode="ResponseRedirect"httpErrors errorMode="Custom" existingResponse="Replace"、REMOVE customErrors誰かが提案しCOMPLETELYとして)、マイクロソフトでお友達に話をした後?

私が言っていたように; これは、54 000以上のビューでかなり人気のある質問のように思われるため、回答をより完全なものにできるとしたらすばらしいでしょう。

更新:ユニコーンの回答は302検出と200 OKを実行し、ルートを使用して404のみを返すように変更することはできません。それは、あまりMVCではない物理ファイルである必要があります。それでは、別のソリューションに移ります。これは究極のMVCであると思われるため、残念です。


1

私のソリューションを追加します。これはHerman Kanのソリューションとほぼ同じですが、小さなしわが私のプロジェクトで機能するようにします。

カスタムエラーコントローラーを作成します。

public class Error404Controller : BaseController
{
    [HttpGet]
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View("404");
    }
}

次に、カスタムコントローラファクトリを作成します。

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
    }
}

最後に、カスタムエラーコントローラーにオーバーライドを追加します。

protected override void HandleUnknownAction(string actionName)
{
    var errorRoute = new RouteData();
    errorRoute.Values.Add("controller", "Error404");
    errorRoute.Values.Add("action", "PageNotFound");
    new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}

以上です。Web.configを変更する必要はありません。


1

1)抽象Controllerクラスを作成します。

public abstract class MyController:Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View("NotFound");
    }

    protected override void HandleUnknownAction(string actionName)
    {
        this.ActionInvoker.InvokeAction(this.ControllerContext, "NotFound");
    }
    protected override void OnAuthorization(AuthorizationContext filterContext) { }
}  

2)すべてのコントローラーでこの抽象クラスから継承します

public class HomeController : MyController
{}  

3)そして、ビュー共有フォルダに「NotFound」という名前のビューを追加します。


0

このスレッドに投稿されたほとんどの解決策を確認しました。この質問は古いかもしれませんが、今でも新しいプロジェクトに非常に当てはまるので、私はここに提示された回答や他の場所での回答を読むのにかなりの時間を費やしました。

@Marcoが404が発生する可能性のあるさまざまなケースを指摘したので、私は一緒にコンパイルしたソリューションをそのリストに対してチェックしました。彼の要件リストに加えて、もう1つ追加しました。

  • ソリューションは、MVCおよびAJAX / WebAPI呼び出しを最も適切な方法で処理できる必要があります。(つまり、MVCで404が発生した場合、「見つかりません」ページが表示され、WebAPIで404が発生した場合、XML / JSON応答を乗っ取って、使用中のJavaScriptが簡単に解析できるようにする必要があります)。

この解決策は2つあります。

その最初の部分はhttps://stackoverflow.com/a/27354140/2310818の @Guillaumeからのものです。彼らのソリューションは、無効なルート、無効なコントローラー、無効なアクションが原因で発生した404を処理します。

アイデアは、Webフォームを作成し、MVCエラーコントローラーのNotFoundアクションを呼び出すことです。これはすべてリダイレクトなしで実行されるため、Fiddlerに単一の302は表示されません。元のURLも保持されるため、このソリューションは素晴らしいものになります。


その2番目の部分は、https: //stackoverflow.com/a/5536676/2310818の@Germánからのものです。これらのソリューションは、アクションによってHttpNotFoundResult()の形式で返された404を処理するか、新しいHttpException()をスローします。

アイデアは、MVCコントローラーによってスローされた応答と例外をフィルターで調べ、エラーコントローラーで適切なアクションを呼び出すことです。このソリューションもリダイレクトなしで機能し、元のURLは保持されます!


ご覧のとおり、これらのソリューションはどちらも非常に堅牢なエラー処理メカニズムを提供し、@ Marcoによってリストされているすべての要件と私の要件を実現しています。このソリューションの実際のサンプルまたはデモをご覧になりたい場合は、コメントを残してください。一緒にまとめさせていただきます。


0

すべての記事を読みましたが、何もうまくいきません:要件のユーザーがURLカスタム404ページに何かを入力すると、表示されるはずです。

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

私はこの記事が非常に有用であることを発見しました。すぐに読む必要があります。カスタマーエラーページ-ベンフォスター

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