customerrors =“ On”の場合、Application_Errorが発生しない


124

エラーが発生したときに実行され、エラーの詳細を自分にメールで送信するコードが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_Errorときに誰もが発砲しない理由を誰かが示唆できますか?customErrorsweb.config


私はまったく同じ問題を抱えています。また、このSOの質問を見つけました:stackoverflow.com/questions/3713939/…これは、IIS7サーバーをクラシックモードにすることを示唆しています。残念ながら、それは私たちの選択肢ではありません。誰かより良い解決策がありますか?
Jesse Webb

ここでは別の関連質問があり、それには答えを(受け入れられいずれも)すべて...でのApplication_Error()を使用しないことをお勧めだstackoverflow.com/questions/1194578/...
ジェシー・ウェッブ

@Gweebz私はこれをどのように回避したかについての回答を投稿しましたが、なぜ私がこの動作をしているのかについての確かなドキュメントはまだ見つかりませんでした。
WDuffy 2011

Application_Error()メソッドが呼び出されなかった理由を説明する回答を追加しました。最終的な解決策についても説明しました。
Jesse Webb

カスタムエラーを機能させるために、この記事を本当にお勧めします。
ThomasArdal

回答:


133

更新
この回答は解決策を提供するので、私はそれを編集しませんが、この問題を解決するはるかにきれいな方法を見つけました。詳細については、他の回答を参照してください...

元の回答:メソッドが呼び出されない
理由がわかりました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ファイルにいくつかのロジックを持っています。このロジックは、ルートのマッピングとフィルターの登録に使用されます。デフォルトでは、フィルターを1つだけ登録しHandleErrorAttributeます。customErrorsがオンの場合(またはRemoteOnlyに設定されている場合はリモート要求を介して)、HandleErrorAttributeはMVCにエラービューを探すように指示し、Application_Error()メソッドを呼び出すことはありません。これに関するドキュメントは見つかりませんでしたが、programmers.stackexchange.comのこの回答で説明されています

未処理の例外ごとに呼び出される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.aspxPageNotFound.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を押すことで直接アクセスできます。

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

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


2
+1!本当に良い回避策ですが、MVCとaspxページを混在させるとどうなりますか?
ディエゴ

2
これはPRODで数か月前から発生しており、マイナスの影響はありません。唯一の「問題」は、MVCはそれを必要としないため、CIを変更して、AspCompile MSBUILDタスクを実行するために展開する必要があったことですが、.asファイルを追加すると、必要でした。他にも問題かもしれないが、彼らは...まだ表面化していない
ジェシー・ウェッブ

私はMVC4でこのアプローチを使用しようとしましたが、どうやらそれは私がを手に入れたときにのみ機能します<customErrors mode="Off" />。たfilters.Add(new HandleErrorAttribute());効果がありません削除またはありません。
GrzegorzSławecki14年

aspxページで、表示するビューを呼び出すajax呼び出しを追加できます。コードの複製が
Mike

71

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

6
+1この答えが機能する場合、間違いなく私はエラーを処理するための最もエレガントでおそらく意図された方法(MVCフレームワークによる)のように思えます。
Matt Hamsmith、

2
これは私にとって完璧に機能し、ここで受け入れられた答えよりもはるかにきれいです。いいね!
アレックスウォーレン

3
これは、例外のロギングの問題を解決するのに役立ちます。これをカスタムエラーページの表示とどのように組み合わせましたか?
ジェシーウェッブ

3
私はこれを試してみましたが、404の場合を除いてうまくいきました。404の場合、Errors.cshtmlビューは表示されず、YSoDしか表示されません。カスタム404が不要な場合、このソリューションは間違いなくよりクリーンです!
Jesse Webb

1
私はそれが好きです。'CustomErrors = On'で動作します
Illidan '22

36

例外をログに記録する機能を妨げない、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>

私もcustomErrors持っているように構成しましたmode="Off"(記事で提案されています)。

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

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

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

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

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

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

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フレームワークと戦っているように感じられなかったので、気に入っています。このソリューションは実際にそれを活用しています!


6
このソリューションはIIS 7以降でのみ機能すると思います。httpErrors要素が最近追加されました。
Jesse Webb

この回答はうまくHTTP Error 500.0 - Internal Server Error The page cannot be displayed because an internal server error has occurred./Error/Index
いき

@SerjSagan新しいプロジェクトでこれを試して、手順をテストしたところ、問題なく動作しました。IIS、IIS Express、またはVS Dev Serverを使用していますか?これはVS Dev Serverでは機能しません。IISではなくVS Dev Serverを使用するようにプロジェクトを設定していたとき、カスタムエラーページではなく、黄色の画面エラーに気付きました。
Jesse Webb

1
@SerjSaganしかし、古典的な黄色の画面エラーではなく、IISの青い画面エラーが発生しているようです。これにより、何らかの形のIISを使用していることが前提になります。その場合は、最初の文でリンクした記事、特に最後のセクション「重要な注意事項が少ない」を読んでください。それは言う:To able to overwrite global settings in global IIS settings (file: C:\Windows\System32\inetsrv\config \applicationHost.config) should be: <section name="httpErrors" overrideModeDefault="Allow" />
ジェシーウェッブ

3
@SerjSagan errorModeをDetailedLocalOnlyまたはCustomに変更すると、ページが表示されます。
ダニエルP

8

以下の場合は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.csありApp_Startます。


1

MarkのExceptionFilterによる回答が好きですが、すべてのコントローラーが同じ基本コントローラーから派生している場合、別のオプションは、基本コントローラーのOnExceptionをオーバーライドすることです。あなたはそこにあなたのロギングと電子メールを送ることができます。これには、IoCコンテナーを使用してベースコントローラーに既に注入されている依存関係を使用できるという利点があります。

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


0

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

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

たくさんの情報がここにあります:http : //support.microsoft.com/kb/306355


Chrisに感謝します。ドキュメントを読んだところ、未処理のエラーが発生するとApplication_Errorが呼び出され(予想通り)、Server.ClearError()を呼び出さないようにすると、web.config customErrorsセクションが最後のハンドルポイントになります。ただし、customErrorsを有効にすると、Application_Errorの起動が停止します。
WDuffy 2011年

あなたがリンクしたドキュメントはASP.NETアプリケーションについて話しており、MVC3 Webアプリケーションの動作が異なっているようです。
Jesse Webb

0

これを回避するために、customerrorsを無効にしたままにし、global.asaxのApplication_Errorイベントからのすべてのエラーを処理しました。MVCでは、301リダイレクトを返すのではなく、適切なエラーコードを返したいので、少し注意が必要です。詳細については、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();
    }

}

私はあなたの解決策を試しましたが、それは私にとってはうまくいきませんでした。の行Response.StatusCode = ###;で、組み込みのMVCエラーページがに表示されていましたC:\inetpub\custerr\en-US。また、Application_Error()メソッドからHttpHandlersまたはControllersを手動で呼び出すという考えも気に入りませんでした。あなたがあなたの問題の解決策を見つけてうれしいです、私はこれがどんな種類の頭痛を私に与えたか知っています。
ジェシーウェッブ

0

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

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は、「コンテンツの長さが大きすぎる」と定義されています。注意すべき重要な点の1つは、maxAllowedContentLengthがバイト単位で指定されていることです。これはmaxRequestLength<system.web>セクションにある設定(キロバイトで指定)とは異なります。

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

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

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


0

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

内部エラーを修正することで、コードApplication_Error()は期待どおりにイベントを続行できました。

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