web-dev-qa-db-ja.com

redirectMode = "ResponseRewrite"を設定すると、CustomErrorsは機能しません。

古いサイトでは、redirectMode="ResponseRewrite"(3.5 SP1の新機能)を追加して、CustomErrorsの動作を変更していました。

<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
</customErrors> 

問題は、一般的なエラーページ(customErrorsを設定しない場合に表示されるページです。redirectMode="ResponseRewrite"部分を削除すると正常に機能することです。

同じサーバーでホストされている他のサイトで同じ設定を使用しているため、3.5 SP1がサーバーにインストールされていると確信しています。

何か案は?

71
Eduardo Molteni

問題はError.aspxにあることがわかりました。それでも、問題の原因となっているerror.aspxの実際のエラーを見つけることができません。

ページを静的なHTMLファイルに変更することで問題を解決しました。

1
Eduardo Molteni

ResponseRewriteが舞台裏でServer.Transferを使用するMVCアプリケーションでこれを行おうとしている人に注意することが重要です。したがって、defaultRedirectはファイルシステム上の正当なファイルに対応する必要があります。どうやら、Server.TransferはMVCルートと互換性がないため、エラーページがコントローラーアクションによって処理される場合、Server.Transferは/ Error/Whateverを探しますが、ファイルシステムでは見つかりません。一般的な404エラーページを返します!

100
Michael Hallock

私にとって完璧に機能した唯一の方法は、カスタムエラーをオフにし、web.configを介してiisのエラーページを置き換えることです。応答とともに正しいステータスコードを送信し、mvcを経由しないという利点があります。

ここにコードがあります

  1. カスタムエラーをオフにする

    <customErrors mode="Off" />
    
  2. エラーページを置き換える

    <httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="404" subStatusCode="-1" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="404" path="Error404.html" responseMode="File" />
      <error statusCode="500" path="Error.html" responseMode="File" />
    </httpErrors>
    

注意。つかいます responsemode="file" URLがファイルへの直接リンクの場合

info: http://tipila.com/tips/use-custom-error-pages-aspnet-mvc

48
Amila

何が起こっているのかIISはエラーステータスコードを取得し、自分ではなく独自のエラーページを表示しています。解決するには、エラーページのコードビハインドページでこれを設定して、IISがこれを実行しないようにする必要があります。

Response.TrySkipIisCustomErrors = true;

これはIIS7以上でのみ機能します。IISの以前のバージョンでは、エラーページの設定を試す必要があります。

20
Michael

Server.Transferに依存しているため、ResponseRewriteの内部実装はMVCと互換性がないようです。

これは目立った機能ホールのように思えるので、HTTPモジュールを使用してこの機能を再実装し、機能するように決定しました。以下のソリューションでは、通常の場合と同じように、有効なMVCルート(物理ファイルを含む)にリダイレクトすることでエラーを処理できます。

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

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>
14
Red Taz

私はこの質問が少し古いことを知っていますが、これを機能させるために静的ファイルである必要はないと指摘すべきだと思いました。

私は同様のことに遭遇しましたが、使用しているマスターページがセッションデータに依存しており、ResponseRewriteが設定されたときにセッションが利用できないため、Error.aspxでそのエラーを見つけるだけの問題ですError.aspxページ。

このセッションが利用できないのは、特定のアプリ構成によるものなのか、ASP.netの「設計による」部分によるものなのか、まだ解決していません。

9
Chris

ASP.NET MVCコントローラーにクエリを転送するエラーページをaspxに作成しました。このaspxページにクエリを書き換えると、クエリがカスタムコントローラーに転送されます。

protected void Page_Load(object sender, EventArgs e)
{
  //Get status code
  var queryStatusCode = Request.QueryString.Get("code");
  int statusCode;
  if (!int.TryParse(queryStatusCode, out statusCode))
  {
    var lastError = Server.GetLastError();
    HttpException ex = lastError as HttpException;
    statusCode = ex == null ? 500 : ex.GetHttpCode();
  }
  Response.StatusCode = statusCode;

  // Execute a route
  RouteData routeData = new RouteData();
  string controllerName = Request.QueryString.Get("controller") ?? "Errors";
  routeData.Values.Add("controller", controllerName);
  routeData.Values.Add("action", Request.QueryString.Get("action") ?? "Index");

  var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
  IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName);
  controller.Execute(requestContext);
}

詳細はこちらをご覧ください: https://stackoverflow.com/a/27354140/1435

1
Guillaume

RedirectMode = "ResponseRewrite"を使用する場合は、web.configファイルの書き換え領域に何かを追加する必要があることがわかりました。問題はあなたのサイトが壊れたときです!サイトは書き換えを処理する「virtual.aspx」を呼び出すことができないため、URL書き換えはできません。

0
Colin Wiseman

私の特定の場合、エラーページには、セッションを使用しようとしたユーザーコントロールを持つマスターページがありました。 Sessionが使用できない場合、HttpExceptionが表示されます。「セッション状態は、設定ファイルまたはPageディレクティブでenableSessionStateがtrueに設定されている場合にのみ使用できます。」最も簡単な修正方法は静的htmlに切り替えること、2番目に簡単な修正方法はより簡単なエラーページを使用すること、最も難しい修正方法はエラーページがどこにも想定されていないことを確実に確認することです(たとえば、セッションは例外をスローしません)エラーになる可能性はありません。

0
David Eison