web-dev-qa-db-ja.com

customerrors = "On"のときにApplication_Errorが起動しない

エラーが発生したときに実行され、エラーの詳細を自分にメールで送信するglobal.asaxファイルのApplication_Errorイベントにコードがあります。

void Application_Error(object sender, EventArgs e)
{
    var error = Server.GetLastError();

    if (error.Message != "Not Found")
    {
        // Send email here...
    }

}

Visual Studioで実行している場合、これは正常に機能しますが、ライブサーバーに発行するとApplication_Errorイベントは発生しません。

いくつかのテストの後、Application_Errorを設定するとcustomErrors="Off"が発生しますが、customErrors="On"に戻すと、イベントは再び発生しなくなります。

Application_ErrorcustomErrorsが有効になっているときにweb.configが起動しない理由を提案できますか?

123
WDuffy

[〜#〜] update [〜#〜]
この回答は解決策を提供するので、それを編集しませんが、この問題を解決するはるかにクリーンな方法を見つけました。詳細については my other answer を参照してください...

元の答え:
Application_Error()メソッドが呼び出されない理由を見つけました...

Global.asax.cs

_public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); // this line is the culprit
    }
...
}
_

デフォルトでは(新しいプロジェクトが生成されるとき)、MVCアプリケーションは_Global.asax.cs_ファイルにいくつかのロジックを持っています。このロジックは、ルートのマッピングとフィルターの登録に使用されます。デフォルトでは、HandleErrorAttributeフィルターという1つのフィルターのみを登録します。 customErrorsがオンの場合(またはRemoteOnlyに設定されている場合はリモート要求を介して)、HandleErrorAttributeはMVCにエラービューを探すように指示し、Application_Error()メソッドを呼び出しません。このドキュメントは見つかりませんでしたが、 programmers.stackexchange.comでのこの回答 で説明されています。

every未処理の例外を呼び出すApplicationError()メソッドを取得するには、HandleErrorAttributeフィルターを登録する行を削除します。

問題は次のとおりです:customErrorsを設定して、必要なものを取得する方法...

CustomErrorsセクションのデフォルトは_redirectMode="ResponseRedirect"_です。 defaultRedirect属性をMVCルートとして指定することもできます。私は非常にシンプルなErrorControllerを作成し、web.configを次のように変更しました...

web.config

_<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
  <error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
_

このソリューションの問題は、エラーURLに302リダイレクトを行い、それらのページが200ステータスコードで応答することです。これにより、Googleはエラーページのインデックスを作成しますが、これは不適切です。また、HTTP仕様にあまり準拠していません。私がやりたかったのはリダイレクトではなく、カスタムエラービューで元の応答を上書きしました。

_redirectMode="ResponseRewrite"_を変更しようとしました。残念ながら、 このオプションはMVCルートをサポートしません 、静的HTMLページまたはASPXのみです。最初は静的なHTMLページを使用しようとしましたが、応答コードはまだ200でしたが、少なくともリダイレクトされませんでした。それから私は この答え ...からアイデアを得た.

エラー処理のためにMVCをあきらめることにしました。 _Error.aspx_と_PageNotFound.aspx_を作成しました。これらのページは非常にシンプルでしたが、1つの魔法がありました...

_<script type="text/C#" runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
    }
</script>
_

このブロックは、ページに正しいステータスコードを提供するよう指示します。おおまかに言って、PageNotFound.aspxページでは、代わりに_HttpStatusCode.NotFound_を使用しました。 web.configを次のように変更しました...

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

すべて完璧に機能しました!

要約:

  • 次の行を削除します:filters.Add(new HandleErrorAttribute());
  • Application_Error()メソッドを使用して例外をログに記録します
  • ASPXページを指すResponseRewriteでcustomErrorsを使用する
  • ASPXページに独自の応答ステータスコードの責任を負わせる

このソリューションには、いくつかの欠点があります。

  • ASPXページはRazorテンプレートとマークアップを共有できません。一貫したルックアンドフィールのために、Webサイトの標準ヘッダーとフッターマークアップを書き換える必要がありました。
  • * .aspxページには、URLを押すことで直接アクセスできます。

これらの問題には回避策がありますが、余分な作業を行うほど心配していませんでした。

これが皆さんのお役に立てば幸いです!

131
Jesse Webb

ExceptionFilterを作成し、Application_Errorの代わりにエラーをログに記録することでこれを解決しました。必要なのは、RegisterGlobalFiltersにinの呼び出しを追加することだけです

log4netExceptionFilter.cs

using System
using System.Web.Mvc;

public class log4netExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        Exception ex = context.Exception;
        if (!(ex is HttpException)) //ignore "file not found"
        {
            //Log error here
        }
    }
}

Global.asax.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new log4netExceptionFilter()); //must be before HandleErrorAttribute
    filters.Add(new HandleErrorAttribute());
}
68
Mark

記事 を見つけました。これは、例外をログに記録する機能を妨げないMVC3 Webアプリでカスタムエラーページを作成するはるかにクリーンな方法を説明しています。

解決策は、<httpErrors>セクションの <system.webServer> 要素を使用することです。

私はWeb.configをそのように設定しました...

<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="-1" />
  <remove statusCode="500" subStatusCode="-1" />
  <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
  <error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>

また、customErrorsmode="Off"を持つように構成しました(記事で提案されているとおり)。

これにより、ErrorControllerのアクションによって応答がオーバーライドされます。そのコントローラーは次のとおりです。

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult NotFound()
    {
        return View();
    }
}

ビューは非常に単純で、標準のRazor構文を使用してページを作成しました。

MVCでカスタムエラーページを使用するには、それだけで十分です。

また、例外のログが必要だったので、カスタムExceptionFilterを使用する Markのソリューション を盗みました...

public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;
        var request = exceptionContext.HttpContext.Request;
        // log stuff
    }
}

最後に行う必要があるのは、Global.asax.csファイルに例外フィルターを登録することです。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new ExceptionPublisherExceptionFilter());
    filters.Add(new HandleErrorAttribute());
}

これは、以前の回答よりもはるかにクリーンなソリューションのように感じられ、私が知る限りではうまく機能します。 MVCフレームワークと戦っている気がしなかったので、特に気に入っています。このソリューションは実際にそれを活用しています!

35
Jesse Webb

ASP.NET MVC5の場合

public class ExceptionPublisherExceptionFilter : IExceptionFilter
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        public void OnException(ExceptionContext exceptionContext)
        {
            var exception = exceptionContext.Exception;
            var request = exceptionContext.HttpContext.Request;
            // HttpException httpException = exception as HttpException;
            // Log this exception with your logger
            _logger.Error(exception.Message);
        }
    }

FilterConfig.csApp_Startフォルダーにあります。

8
Developer

ExceptionFilterを使用したMarkの答えは気に入っていますが、すべてのコントローラーが同じベースコントローラーから派生している場合は、ベースコントローラーでOnExceptionをオーバーライドするだけです。ロギングと電子メール送信をそこで行うことができます。これには、既にIoCコンテナーを使用してベースコントローラーに注入した依存関係を使用できるという利点があります。

IExceptionFilterでIoCを使用することはできますが、バインディングを構成するのは少し複雑です。

1
Tim Hardy

これを回避するために、customerrorsを無効にして、global.asaxのApplication_Errorイベントからのすべてのエラーを処理することになりました。 301リダイレクトを返したくなかったため、MVCでは少し注意が必要で、適切なエラーコードを返しました。詳細については、私のブログの http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-をご覧ください。 handle-errors / しかし、最終的なコードは以下にリストされています...

void Application_Error(object sender, EventArgs e)
{
    var error = Server.GetLastError();
    var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

    if (code != 404)
    {
            // Generate email with error details and send to administrator
    }

    Response.Clear();
    Server.ClearError();

    string path = Request.Path;
    Context.RewritePath(string.Format("~/Errors/Http{0}", code), false);
    IHttpHandler httpHandler = new MvcHttpHandler();
    httpHandler.ProcessRequest(Context);
    Context.RewritePath(path, false);
}

そして、ここにコントローラーがあります

public class ErrorsController : Controller
{

    [HttpGet]
    public ActionResult Http404(string source)
    {
            Response.StatusCode = 404;
            return View();
    }

    [HttpGet]
    public ActionResult Http500(string source)
    {
            Response.StatusCode = 500;
            return View();
    }

}
0
WDuffy

Application_Error()がヒットしなかった同じ問題を抱えていました。私はすべてを試しましたが、最終的には何が起こっているのかを確認しました。 ELMAHイベントに、送信する電子メールにJSONを追加するカスタムコードがあり、そこにnullエラーがありました!

内部エラーを修正することで、コードは予想どおりApplication_Error()イベントに進むことができました。

0
Matt Kemp

このブログエントリは私を助けてくれました:

http://asp-net.vexedlogic.com/2011/04/23/asp-net-maximum-request-length-exceeded/

IIS 7.0以上を使用している場合、Web.configファイルを変更して、大きすぎる要求を処理できます。いくつかの注意事項がありますが、以下に例を示します。

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="1048576" />
    </requestFiltering>
  </security>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="13" />
    <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/UploadTooLarge.htm" responseMode="Redirect" />
  </httpErrors>
</system.webServer>

これらの構成ファイル要素に関する追加の詳細がここにあります:

http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/requestLimits

ステータスコード404.13は、「Content Length Too Large」として定義されています。注意すべき重要な点は、maxAllowedContentLengthがバイト単位で指定されることです。これは、キロバイト単位で指定される<system.web>セクションにあるmaxRequestLength設定とは異なります。

<system.web>
  <httpRuntime maxRequestLength="10240" />
</system.web>

また、pathresponseModeの場合、Redirect属性は絶対パスである必要があるため、必要に応じて仮想ディレクトリ名を追加します。 Jesse Webbの有益な回答は、responseMode="ExecuteURL"を使用してこれを行う方法を示しており、そのアプローチもうまくいくと思います。

Visual Studio開発サーバー(Cassini、Visual Studioに統合されたWebサーバー)を使用して開発している場合、このアプローチは機能しません。私はそれがIIS Expressで動作すると仮定していますが、私はそれをテストしていません。

0
Dan Jagnow

私が知る限り、urlパラメーターで指定されたページに制御を渡しているので、Application_Errorではなく、イベント通知がここに置かれます。

<customErrors defaultRedirect="myErrorPage.aspx"
              mode="On">
</customErrors>

多くの情報がここにあります: http://support.Microsoft.com/kb/306355

0
ChrisBint