ASP.NET 自定义错误页面 - Server.GetLastError() 为 null

发布于 2024-07-10 00:21:51 字数 543 浏览 5 评论 0原文

我为我的应用程序设置了一个自定义错误页面:

<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() is null

有什么方法可以在错误页面上获取异常详细信息,而不是在 Global.asax.cs 中?

Vista/IIS7 上的 ASP.NET 3.5

I have a custom error page set up for my application:

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

In Global.asax, Application_Error(), the following code works to get the exception details:

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

By the time I get to my error page (~/errors/GeneralError.aspx.cs), Server.GetLastError() is null

Is there any way I can get the exception details on the Error Page, rather than in Global.asax.cs ?

ASP.NET 3.5 on Vista/IIS7

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

小清晰的声音 2024-07-17 00:21:52

虽然这里有几个很好的答案,但我必须指出,在错误页面上显示系统异常消息并不是一个好的做法(我假设您想要这样做)。 您可能会无意中向恶意用户透露您不希望透露的信息。 例如Sql Server异常消息非常详细,可以给出发生错误时数据库的用户名、密码和模式信息。 该信息不应显示给最终用户。

Whilst there are several good answers here, I must point out that it is not good practice to display system exception messages on error pages (which is what I am assuming you want to do). You may inadvertently reveal things you do not wish to do so to malicious users. For example Sql Server exception messages are very verbose and can give the user name, password and schema information of the database when an error occurs. That information should not be displayed to an end user.

微暖i 2024-07-17 00:21:52

这是我的解决方案..

在 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;
        }
    }

Here is my solution..

In 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"); 
    }

In 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;
        }
    }
混浊又暗下来 2024-07-17 00:21:52

我认为每个人都忽略了一个重要的考虑因素,那就是负载平衡(网络场)场景。 由于执行 global.asax 的服务器可能与执行自定义错误页面的服务器不同,因此将异常对象存储在应用程序中并不可靠。

我仍在寻找网络场配置中此问题的可靠解决方案,和/或 MS 的良好解释,说明为什么您无法像您一样在自定义错误页面上使用 Server.GetLastError 来获取异常在 global.asax Application_Error 中。

PS 如果不先锁定然后解锁,将数据存储在 Application 集合中是不安全的。

One important consideration that I think everybody is missing here is a load-balancing (web farm) scenario. Since the server that's executing global.asax may be different than the server that's about the execute the custom error page, stashing the exception object in Application is not reliable.

I'm still looking for a reliable solution to this problem in a web farm configuration, and/or a good explanation from MS as to why you just can't pick up the exception with Server.GetLastError on the custom error page like you can in global.asax Application_Error.

P.S. It's unsafe to store data in the Application collection without first locking it and then unlocking it.

甜是你 2024-07-17 00:21:52

这对我有用。 在 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中创建文件夹错误
并在 ~\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
打开页面没有错误


如果发生错误
发生错误

可以将变量“log”存储在数据库中,而不是显示错误

来源:微软 ASP.Net

It worked for me. in MVC 5

in ~\Global.asax

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

in ~\Controllers Create ErrorController.cs

using System.Web.Mvc;

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

in ~\Models Create 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;
        }
    }
}

in ~\Views Create Folder Error
and in ~\Views\Error Create 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>
    }
}

If you enter this address localhost/Error
open page Whithout Error


And if an error occurs
error occurs

As can be instead of displaying errors, variable 'log' to be stored in the database

Source: Microsoft ASP.Net

扛刀软妹 2024-07-17 00:21:52

这与下面的这两个主题相关,我想在错误页面上同时获取 GetHtmlErrorMessage 和 Session 。

ResponseRewrite 后会话为空

为什么当redirectMode = ResponseRewrite时HttpContext.Session为空

我尝试并看到不需要的解决方案Server.Transfer() 或 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

This related to these 2 topics below, I want get both GetHtmlErrorMessage and Session on Error page.

Session is null after ResponseRewrite

Why is HttpContext.Session null when redirectMode = ResponseRewrite

I tried and see solution which no need Server.Transfer() or Response.Redirect()

First: remove ResponseRewrite in web.config

Web.config

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

Then Global.asax

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

Then 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
            }

For references

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

清风夜微凉 2024-07-17 00:21:52

我认为你在这里有几个选择。

您可以将最后一个异常存储在会话中并从自定义错误页面检索它; 或者您可以直接重定向到 Application_error 事件中的自定义错误页面。 如果您选择后者,您需要确保使用 Server.Transfer 方法。

I think you have a couple of options here.

you could store the last Exception in the Session and retrieve it from your custom error page; or you could just redirect to your custom error page within the Application_error event. If you choose the latter, you want to make sure you use the Server.Transfer method.

少女的英雄梦 2024-07-17 00:21:51

更仔细地查看我的 web.config 设置,这篇文章非常有帮助

在asp.net 3.5 sp1中有一个新参数redirectMode

,因此我们可以修改customErrors来添加此参数:

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

ResponseRewrite模式允许我们在不重定向的情况下加载“错误页面”浏览器,因此 URL 保持不变,对我来说重要的是,异常信息不会丢失。

Looking more closely at my web.config set up, one of the comments in this post is very helpful

in asp.net 3.5 sp1 there is a new parameter redirectMode

So we can amend customErrors to add this parameter:

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

the ResponseRewrite mode allows us to load the «Error Page» without redirecting the browser, so the URL stays the same, and importantly for me, exception information is not lost.

卖梦商人 2024-07-17 00:21:51

好的,我找到了这个帖子:
http://msdn.microsoft.com/en-us/library/aa479319。 aspx

带有这个非常说明性的图表:

diagram
(来源:microsoft.com)

本质上,为了获取这些异常详细信息,我需要将它们自己存储在 Global.asax 中,以便以后在我的自定义错误页面上检索。

似乎最好的方法是在 Global.asax 中完成大部分工作,使用自定义错误页面处理有用的内容而不是逻辑。

OK, I found this post:
http://msdn.microsoft.com/en-us/library/aa479319.aspx

with this very illustrative diagram:

diagram
(source: microsoft.com)

in essence, to get at those exception details i need to store them myself in Global.asax, for later retrieval on my custom error page.

it seems the best way is to do the bulk of the work in Global.asax, with the custom error pages handling helpful content rather than logic.

请别遗忘我 2024-07-17 00:21:51

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>

最后,除了存储在 web.config 中的异常之外,执行您需要执行的任何操作。 >错误页面

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 ...
}

A combination of what NailItDown and Victor said. The preferred/easiest way is to use your Global.Asax to store the error and then redirect to your custom error page.

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
}

In addition, you need to set up your web.config:

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

And finally, do whatever you need to with the exception you've stored in your 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 ...
}
蓝海似她心 2024-07-17 00:21:51

尝试在 global.asax.cs 的 Application_Error() 方法中使用 Server.Transfer("~/ErrorPage.aspx"); 之类的内容,

然后在 中使用ErrorPage.aspx.cs 的 Page_Load() 您应该可以执行以下操作: Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() 似乎让异常一直存在。

Try using something like Server.Transfer("~/ErrorPage.aspx"); from within the Application_Error() method of global.asax.cs

Then from within Page_Load() of ErrorPage.aspx.cs you should be okay to do something like: Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() seems to keep the exception hanging around.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文