126

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

4

9 に答える 9

135

更新
この回答は解決策を提供するため、編集しませんが、この問題を解決するよりクリーンな方法を見つけました。詳細については、他の回答を参照してください...

元の回答:メソッドが呼び出されない
理由がわかりました...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 に Error ビューを探すように指示し、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 をクリックして直接アクセスできます

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

これがみんなに役立つことを願っています!

于 2011-07-29T15:06:26.927 に答える
75

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());
}
于 2011-09-26T06:18:13.630 に答える
37

例外をログに記録する機能を妨げない、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 フレームワークと戦っているような気がしなかったからです。このソリューションは実際にそれを活用しています!

于 2012-03-05T19:41:38.830 に答える
1

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

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

于 2012-01-11T20:32:56.730 に答える
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>

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

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

于 2012-06-08T18:05:17.280 に答える
0

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

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

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

于 2011-06-28T14:54:11.397 に答える
0

これを回避するために、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();
    }

}
于 2011-07-29T10:18:26.007 に答える