ASP.NET MVCのネイティブ404エラーページ

ASP.NET MVCでプロジェクトを開発するとき、独自の404エラーページを作成する必要が生じたため、数分でこのタスクに対処できると期待していました。 6時間の作業の後、複雑さの度合いが異なるソリューションの2つのオプションを特定しました。 以下の説明。



私が使用しているASP.NET MVC 3では、グローバルフィルターが登場しています。 新しいプロジェクトのテンプレートでは、独自のエラーページを表示するためにその使用が既に組み込まれています( HandleErrorAttribute使用 )。 素晴らしい方法ですが、コード404(ページが見つかりません)でエラーを処理することはできません。 したがって、このエラーを処理するための別の美しいオプションを探す必要がありました。



Web.configを介した404エラー処理



ASP.NETプラットフォームは、Web.configファイルの簡単な構成を通じてエラーを任意に処理する機能を提供します。 これを行うには、system.webセクションに次のコードを追加します。

<customErrors mode="On" > <error statusCode="404" redirect="/Errors/Error404/" /> </customErrors>
      
      





404エラーが発生した場合、ユーザーはyoursite.ru/Errors/Error404/?aspxerrorpath=/Not/Found/Urlページに送信されます。 あまり美しくなく、便利ではない(URLを編集できない)という事実に加えて、 habr.ruの記事である SEO にとっても悪いことです。

メソッドは、redirectMode = "ResponseRewrite"をcustomErrorsに追加することにより、わずかに改善できます。

 <customErrors mode="On" redirectMode="ResponseRewrite" > <error statusCode="404" redirect="/Errors/Error404/" /> </customErrors>
      
      





この場合、エラー処理ページへのリダイレクトは発生しませんが、要求されたエラーパスは指定されたページのコンテンツに置き換えられます。 ただし、いくつかの困難があります。 ASP.NET MVCでは、指定された形式のこのメソッドは機能しません。 トピックでかなり詳細な議論(英語)を読むことができます。 つまり、このメソッドはServer.Transferメソッドに基づいており、従来のASP.NETで使用されているため、静的ファイルでのみ機能します。 例のように動的ページでは、ディスク上にファイル「/ Errors / Error404 /」が表示されないため、動作を拒否します。 つまり、「/ Errors / Error404 /」を「/Errors/Error404.htm」などに置き換えると、説明されている方法が機能します。 ただし、この場合、追加のエラー処理アクション(ロギングなど)を実行することはできません。

指定されたトピックでは、各ページに次のコードを追加することが提案されました。

 Response.TrySkipIisCustomErrors = true;
      
      





この方法はIIS 7以降でのみ機能するため、この方法は検証できませんでした。IIS6を使用します。検索を続行する必要がありました。



タンバリンとApplication_Errorで踊る



何らかの理由で上記の方法を適用できない場合、より多くのコード行を記述する必要があります。 部分的な解決策は記事に記載されています

トピックで見つけた「タンバリンを使用した」最も完全なソリューション。 議論は英語ですので、決定のテキストをロシア語に翻訳します。

以下は、404 NotFoundエラー表示の問題を解決するための私の要件です。



Global.asaxのApplication_Errorは、たとえば、未処理の例外やログの処理など、404エラーでは機能しない高レベルの目的に使用する必要があると考えています。したがって、404エラーに関連するすべてのコードをグローバルファイルから除外しようとしています。 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();    //    ('NotFound' route),           model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?      Request.Url.OriginalString : url;    //     Referrer  Request    model.ReferrerUrl = Request.UrlReferrer != null &&      Request.UrlReferrer.OriginalString != model.RequestedUrl ?      Request.UrlReferrer.OriginalString : null;    // TODO:   ILogger    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アクションにリダイレクトする1つの場所です。 DRY方法論を使用してください!

 public abstract class MyController : Controller { #region Http404 handling protected override void HandleUnknownAction(string actionName) { //   - ErrorController,       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 HttpExceptionを処理する


たとえば、次のようになります( 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:アプリケーションが判断できなかったパスのNotFoundルートをGlobal.asaxに追加する


このルートは、 Http404



アクションをトリガーする必要があります。 ルーティングエンジンはドメイン名の部分を切り捨てるため、 url



パラメーターは相対アドレスになることに注意してください。 そのため、最初のステップでこれらすべての条件ステートメントを追加しました。

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





これは、自分では発生しない404エラーをキャッチするためのMVCアプリケーションの3番目で最後の場所です。 ここで、着信パスをコントローラーおよびアクションにマップすることができなかった場合、MVCはこのエラーの処理をASP.NETプラットフォーム(Global.asaxファイル内)にさらに渡します。 そして、私たちはこれが起こることを望まない。



ステップ5:最後に、アプリケーションが何も見つからない場合、エラー404が発生します


たとえば、無効なIDパラメーターがMyControllerから継承されたLoanコントローラーに渡される場合:

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





これらすべてをより少ないコードで実装できれば素晴らしいと思います。 しかし、このソリューションの方が保守、テストが簡単で、全体的にはより便利だと思います。



2番目のソリューションのライブラリ



最後に、上記の方法でエラー処理を整理できるライブラリが既に用意されています。 彼女はここで見つけることができます-github.com/andrewdavey/NotFoundMvc



おわりに



楽しみのために、この問題がOrchardでどのように解決されたかを見ました。 私は驚き、ややがっかりしました-開発者はこの例外をまったく処理しないことに決めました-私の意見では、自分の404エラーページは長い間Web開発の標準になっています。



私のアプリケーションでは、ルーティングを使用してWeb.configでエラー処理を使用しました。 アプリケーションの開発が完了するまで、404エラーの処理に専念するのはかなり危険です。その場合、アプリケーションをリリースすることさえできません。 終わりに近づいて、ほとんどの場合、2番目のソリューションを実装します。



関連リンク:

  1. ASP.NET、HTTP 404およびSEO
  2. redirectMode = "ResponseRewrite"を設定すると、CustomErrorsは機能しません
  3. ASP.NET MVCで404を適切に処理するにはどうすればよいですか?
  4. ASP.NET MVC 3のサイト全体のエラー処理
  5. ASP.NET MVC 404エラー処理
  6. ASP.NET MVCのHandleUnknownAction-注意してください
  7. github.com/andrewdavey/NotFoundMvc



All Articles