ASP.NETカスタムエラーページ-Server.GetLastError()がnull


112

アプリケーションにカスタムエラーページを設定しました。

<customErrors mode="On" defaultRedirect="~/errors/GeneralError.aspx"
/>

Global.asax、Application_Error()では、次のコードが機能して例外の詳細を取得します。

  Exception ex = Server.GetLastError();
  if (ex != null)
    {
        if (ex.GetBaseException() != null)
            ex = ex.GetBaseException();
    }

エラーページ(〜/ errors / GeneralError.aspx.cs)に到達するまでに、Server.GetLastError()はnullです。

Global.asax.csではなく、エラーページで例外の詳細を取得する方法はありますか?

Vista / IIS7上のASP.NET 3.5


Cassiniを搭載したWin7上のASP.NET 4.0にも適用
Marcel

確認済みの回答として「<customErrors mode = "RemoteOnly" defaultRedirect = "〜/ errors / GeneralError.aspx" redirectMode = "ResponseRewrite" />」を
追加

回答:


137

私のweb.config設定をより詳しく見ると、この投稿のコメントの1つは非常に役立ちます

asp.net 3.5 sp1には、redirectModeという新しいパラメーターがあります。

したがってcustomErrors、このパラメーターを追加するように修正できます。

<customErrors mode="RemoteOnly" defaultRedirect="~/errors/GeneralError.aspx" redirectMode="ResponseRewrite" />

このResponseRewriteモードでは、ブラウザーをリダイレクトせずに«エラーページ»を読み込むことができるため、URLは同じままで、重要なのは例外情報が失われないことです。


4
これは私にはうまくいきませんでした。例外情報は失われます。それをApplication_Error()のセッションに格納し、エラーページのPage_Load()ハンドラーに引き戻します。
BrianK、2009

2
それはすべてのドキュメンテーションの標準であるべきです。これはとても良いことで、古い動作をサポートする理由はもうわかりません。ステータスコードが正しい限り、元のリクエストURLをそのままにしておく(ブラウザのリダイレクトを行わない)ことには問題はありません。実際には、応答コードが要求されたURLに関連しており、共有エラーページ要求に関連していないため、HTTPによるとこれはより正確です。ポインタをありがとう、私はその新機能を逃しました!
Tony Wall、

これは、UpdatePanels 内のコントロールによってトリガーされた例外では機能しません。エラーページは表示されなくなります。
サム

2
リダイレクトモードでのこの素敵な1つのResponseRewrite値がAsp.Net 4.5で機能することを証明するために私のコメントを追加する古い回答なので、
Sundara Prabu

38

OK、私はこの投稿を見つけました:http : //msdn.microsoft.com/en-us/library/aa479319.aspx

この非常に説明的な図で:

図
(ソース:microsoft.com

基本的に、これらの例外の詳細を取得するには、後で自分のカスタムエラーページで取得できるように、Global.asaxに自分で保存する必要があります。

最善の方法は、Global.asaxで作業の大部分を行うことであり、カスタムエラーページはロジックではなく役立つコンテンツを処理します。


18

NailItDownとVictorが言ったことの組み合わせ。推奨/最も簡単な方法は、Global.Asaxを使用してエラーを格納し、カスタムエラーページにリダイレクトすることです。

Global.asax

    void Application_Error(object sender, EventArgs e) 
{
    // Code that runs when an unhandled error occurs
    Exception ex = Server.GetLastError();
    Application["TheException"] = ex; //store the error for later
    Server.ClearError(); //clear the error so we can continue onwards
    Response.Redirect("~/myErrorPage.aspx"); //direct user to error page
}

さらに、web.configを設定する必要があります。

  <system.web>
    <customErrors mode="RemoteOnly" defaultRedirect="~/myErrorPage.aspx">
    </customErrors>
  </system.web>

そして最後に、エラーページに保存した例外を除いて、必要なことをすべて実行します

protected void Page_Load(object sender, EventArgs e)
{

    // ... do stuff ...
    //we caught an exception in our Global.asax, do stuff with it.
    Exception caughtException = (Exception)Application["TheException"];
    //... do stuff ...
}

35
それをアプリケーションに保存すると、システムの他のすべてのユーザーはどうなりますか。セッション中じゃないですか?
BrianK、2009

11
確かに、それはアプリケーション[「TheException」]でこれを保管本当に悪いアプローチだ
ジュニアMayhé

4
さらに、ユーザーごとに複数の「タブ」をサポートする場合は、例外をセッションストアで一意のキーに指定し、エラーページにリダイレクトするときに、そのキーをクエリ文字列パラメータとして含めることができます。
Anders Fjeldstad、2011

5
+1しかし、これApplication[]はグローバルオブジェクトであることに注意してください。理論的には、2番目のページがエラーを上書きするという競合状態が発生する可能性があります。ただし、Session[]は常にエラー状態で使用できるわけではないので、これがより良い選択だと思います。
Andomar 2013年

3
例外の保存に使用されるキーに新しいGUIDプレフィックスを追加し、GUIDをパラメーターとしてカスタムエラーページに渡すだけです。
SteveGSD、2015年

6

以下のようなものを使用してみてくださいServer.Transfer("~/ErrorPage.aspx");内からApplication_Error()global.asax.csメソッド

次にPage_Load()、ErrorPage.aspx.cs 内から、次のようなことを行ってもかまいません。Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() 例外がぶらぶらしているようです。


これが私のアプリケーションが行った方法であり、エラーの99%で非常にうまく機能しました。しかし、今日、レンダリングステップ中に発生する例外に遭遇しました。あなたがいる場合Server.Transferのページの後半にレンダリングされ、そのページのHTMLには、あなたは単に、すでにレンダリングされているものは何でもに連結されるために転送します。そのため、ページの半分が壊れ、その下にエラーページが続く場合があります。
Kevin

何らかの理由で、Server.Transfer()を呼び出すと問題が発生し、エラーがまったく表示されません。したがって、この方法の使用はお勧めしません。上記のようにweb.config行を使用するだけで(<customErrors mode = "RemoteOnly" defaultRedirect = "〜/ errors / GeneralError.aspx" redirectMode = "ResponseRewrite" />)、正常に機能します
Naresh Mittal

5

ここにはいくつかの良い答えがありますが、システム例外メッセージをエラーページに表示することはお勧めしません(これは私があなたがやりたいと思っていることです)。意図しないことを悪意のあるユーザーに誤って明らかにする可能性があります。たとえば、SQL Serverの例外メッセージは非常に詳細であり、エラーが発生したときにデータベースのユーザー名、パスワード、スキーマ情報を提供できます。その情報はエンドユーザーに表示されるべきではありません。


1
私の場合、バックエンドで使用するための例外情報のみが必要でしたが、それは良いアドバイスです。
11

2
質問には答えません。
Arne Evertsson、2015年

5

これが私の解決策です。

Global.aspxの場合:

void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs

        //direct user to error page 
        Server.Transfer("~/ErrorPages/Oops.aspx"); 
    }

Oops.aspxで:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadError(Server.GetLastError()); 
    }

    protected void LoadError(Exception objError)
    {
        if (objError != null)
        {
            StringBuilder lasterror = new StringBuilder();

            if (objError.Message != null)
            {
                lasterror.AppendLine("Message:");
                lasterror.AppendLine(objError.Message);
                lasterror.AppendLine();
            }

            if (objError.InnerException != null)
            {
                lasterror.AppendLine("InnerException:");
                lasterror.AppendLine(objError.InnerException.ToString());
                lasterror.AppendLine();
            }

            if (objError.Source != null)
            {
                lasterror.AppendLine("Source:");
                lasterror.AppendLine(objError.Source);
                lasterror.AppendLine();
            }

            if (objError.StackTrace != null)
            {
                lasterror.AppendLine("StackTrace:");
                lasterror.AppendLine(objError.StackTrace);
                lasterror.AppendLine();
            }

            ViewState.Add("LastError", lasterror.ToString());
        }
    }

   protected void btnReportError_Click(object sender, EventArgs e)
    {
        SendEmail();
    }

    public void SendEmail()
    {
        try
        {
            MailMessage msg = new MailMessage("webteam", "webteam");
            StringBuilder body = new StringBuilder();

            body.AppendLine("An unexcepted error has occurred.");
            body.AppendLine();

            body.AppendLine(ViewState["LastError"].ToString());

            msg.Subject = "Error";
            msg.Body = body.ToString();
            msg.IsBodyHtml = false;

            SmtpClient smtp = new SmtpClient("exchangeserver");
            smtp.Send(msg);
        }

        catch (Exception ex)
        {
            lblException.Text = ex.Message;
        }
    }

4

ここで誰もが欠けていると私が考える重要な考慮事項の1つは、負荷分散(Webファーム)シナリオです。global.asaxを実行しているサーバーは、カスタムエラーページを実行しているサーバーとは異なる場合があるため、アプリケーションで例外オブジェクトをスタッシュすることは信頼できません。

Webファーム構成におけるこの問題の信頼できる解決策、および/またはカスタムエラーページでServer.GetLastErrorを使用して例外を取得できない理由についてのMSからの適切な説明を探していますglobal.asax Application_Error。

PS最初にロックしてからロック解除せずにApplicationコレクションにデータを格納するのは安全ではありません。


これは、クライアント側のリダイレクトを行う場合にのみ当てはまります。サーバー転送を行う場合、それはすべて1つの要求の一部であるため、application_error-> page_loadはすべて、ファーム内の1つのサーバーで順番に発生します。
davewasthere 2017年

2

これは以下の2つのトピックに関連しており、GetHtmlErrorMessageとSession on Errorページの両方を取得します。

ResponseRewrite後のセッションはnullです

redirectMode = ResponseRewriteのときにHttpContext.Sessionがnullになるのはなぜですか

私は試しましたが、必要のない解決策を見ました Server.Transfer() or Response.Redirect()

まず、web.configのResponseRewriteを削除します。

Web.config

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

次にGlobal.asax

    void Application_Error(object sender, EventArgs e)
    {
         if(Context.IsCustomErrorEnabled)
         {     
            Exception ex = Server.GetLastError();
            Application["TheException"] = ex; //store the error for later
         }
    }

次にerrorHandler.aspx.cs

        protected void Page_Load(object sender, EventArgs e)
            {       
                string htmlErrorMessage = string.Empty ;
                Exception ex = (Exception)Application["TheException"];
                string yourSessionValue = HttpContext.Current.Session["YourSessionId"].ToString();

                //continue with ex to get htmlErrorMessage 
                if(ex.GetHtmlErrorMessage() != null){              
                    htmlErrorMessage = ex.GetHtmlErrorMessage();
                }   
                // continue your code
            }

参考のために

http://www.developer.com/net/asp/article.php/3299641/ServerTransfer-Vs-ResponseRedirect.htm


2

それは私のために働いた。MVC 5


~\Global.asax

void Application_Error(object sender, EventArgs e)
{
    FTools.LogException();
    Response.Redirect("/Error");
}


~\Controllers作成します。ErrorController.cs

using System.Web.Mvc;

namespace MVC_WebApp.Controllers
{
    public class ErrorController : Controller
    {
        // GET: Error
        public ActionResult Index()
        {
            return View("Error");
        }
    }
}


~\Models作成します。FunctionTools.cs

using System;
using System.Web;

namespace MVC_WebApp.Models
{
    public static class FTools
    {
        private static string _error;
        private static bool _isError;

        public static string GetLastError
        {
            get
            {
                string cashe = _error;
                HttpContext.Current.Server.ClearError();
                _error = null;
                _isError = false;
                return cashe;
            }
        }
        public static bool ThereIsError => _isError;

        public static void LogException()
        {
            Exception exc = HttpContext.Current.Server.GetLastError();
            if (exc == null) return;
            string errLog = "";
            errLog += "**********" + DateTime.Now + "**********\n";
            if (exc.InnerException != null)
            {
                errLog += "Inner Exception Type: ";
                errLog += exc.InnerException.GetType() + "\n";
                errLog += "Inner Exception: ";
                errLog += exc.InnerException.Message + "\n";
                errLog += "Inner Source: ";
                errLog += exc.InnerException.Source + "\n";
                if (exc.InnerException.StackTrace != null)
                {
                    errLog += "\nInner Stack Trace: " + "\n";
                    errLog += exc.InnerException.StackTrace + "\n";
                }
            }
            errLog += "Exception Type: ";
            errLog += exc.GetType().ToString() + "\n";
            errLog += "Exception: " + exc.Message + "\n";
            errLog += "\nStack Trace: " + "\n";
            if (exc.StackTrace != null)
            {
                errLog += exc.StackTrace + "\n";
            }
            _error = errLog;
            _isError = true;
        }
    }
}


中に~\Viewsフォルダを作成Error し、中に~\Views\Error作成しますError.cshtml

@using MVC_WebApp.Models
@{
    ViewBag.Title = "Error";
    if (FTools.ThereIsError == false)
    {
        if (Server.GetLastError() != null)
        {
            FTools.LogException();
        }
    }
    if (FTools.ThereIsError == false)
    {
        <br />
        <h1>No Problem!</h1>
    }
    else
    {
        string log = FTools.GetLastError;
        <div>@Html.Raw(log.Replace("\n", "<br />"))</div>
    }
}


このアドレスを入力すると localhost/Error エラーを開くページを開く



エラーが発生した場合 エラーが発生する

エラーを表示する代わりに、データベースに保存される変数「ログ」


出典:Microsoft ASP.Net


1

ここにはいくつかの選択肢があると思います。

最後の例外をセッションに保存し、カスタムエラーページから取得できます。または、Application_errorイベント内のカスタムエラーページにリダイレクトすることもできます。後者を選択する場合は、必ずServer.Transferメソッドを使用する必要があります。

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