web-dev-qa-db-ja.com

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

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

<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

110
nailitdown

Web.configのセットアップを詳しく見ると、 この投稿は非常に役に立ちます

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

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

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

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

136
nailitdown

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

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

diagram
(ソース: Microsoft.com

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

global.asaxで大部分の作業を行うのが最良の方法であるようです。カスタムエラーページは、ロジックではなく有用なコンテンツを処理します。

36
nailitdown

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>

そして最後に、error pageに保存した例外を除いて、必要なことをすべて行います。

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 ...
}
18
rlb.usa

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

次に、ErrorPage.aspx.csのPage_Load()内から、次のようなことをしても大丈夫です:Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer()は例外をぶら下げているようです。

6
Ross Oliver

ここに私の解決策があります。

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;
        }
    }
5
user825345

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

5
Phil

ここで皆が不足していると思う重要な考慮事項の1つは、負荷分散(Webファーム)シナリオです。 global.asaxを実行しているサーバーは、カスタムエラーページの実行に関するサーバーとは異なる場合があるため、Applicationで例外オブジェクトを隠蔽することは信頼できません。

私はまだWebファーム構成のこの問題に対する信頼できる解決策、および/またはカスタムエラーページのServer.GetLastErrorで例外をピックアップできない理由に関するMSからの良い説明を探していますglobal.asax Application_Errorで。

追伸最初にデータをロックしてからロックを解除せずに、アプリケーションコレクションにデータを保存することは安全ではありません。

4
Leonard Lobel

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

ResponseRewrite後のセッションはnull

redirectMode = ResponseRewriteのときにHttpContext.Sessionがヌルになる理由

私は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
Bao

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


in ~\Global.asax

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


in ~\Controllers作成ErrorController.cs

using System.Web.Mvc;

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


in ~\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/Erroropen page Whithout Error



そしてエラーが発生した場合error occurs

エラーを表示する代わりに、変数「log」をデータベースに保存することができます


ソース: Microsoft ASP.Net

2
M.R.T2017

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

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

1
Victor