【问题标题】:ASP.NET custom error page - Server.GetLastError() is nullASP.NET 自定义错误页面 - Server.GetLastError() 为空
【发布时间】:2010-09-25 11:22:59
【问题描述】:

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

<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() 为空

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

Vista/IIS7 上的 ASP.NET 3.5

【问题讨论】:

  • 也适用于带有 Cassini 的 Win7 上的 ASP.NET 4.0
  • 添加“" 作为确认答案

标签: asp.net exception web-applications custom-error-pages


【解决方案1】:

仔细查看我的 web.config 设置,this post is very helpful 中的 cmets 之一

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

所以我们可以修改customErrors添加这个参数:

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

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

【讨论】:

  • 这对我不起作用。异常信息丢失。我会将它存储在 Application_Error() 的会话中,然后在我的错误页面的 Page_Load() 处理程序中将其拉回。
  • 这应该是所有文档中的规范。这太好了,我认为没有理由再支持旧行为了。只要状态代码正确,保持原始请求 URL 不变(不进行浏览器重定向)应该没有问题。事实上,根据 HTTP 更正确,因为响应代码与请求的 URL 相关,而不是共享错误页面请求。感谢您的指点,我错过了那个新功能!
  • 这不适用于UpdatePanels 中的控件触发的异常;错误页面将不再显示。
  • 因为它是一个旧答案,添加我的评论以证明重定向模式中的这个很好的 ResponseRewrite 值在 Asp.Net 4.5 中有效
【解决方案2】:

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

这个非常说明性的图表:


(来源:microsoft.com

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

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

【讨论】:

    【解决方案3】:

    结合了 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 ...
    }
    

    【讨论】:

    • 如果将其存储在应用程序中,那么系统的所有其他用户呢?不应该在会话中吗?
    • 确实,在 Application["TheException"] 上存储它是一种非常糟糕的方法
    • 另外,如果您想为每个用户支持多个“选项卡”,您可能希望在会话存储中为异常提供一个唯一键,然后在重定向到错误时将该键作为查询字符串参数包含在内页面。
    • +1 但请注意 Application[] 是一个全局对象。从理论上讲,您可能会遇到第二页覆盖错误的竞争条件。但是,由于Session[] 在错误情况下并不总是可用,我认为这是更好的选择。
    • 只需将新的 GUID 前缀添加到用于存储异常的键中,并将 GUID 作为参数传递给自定义错误页面。
    【解决方案4】:

    尝试在 global.asax.cs 的 Application_Error() 方法中使用类似 Server.Transfer("~/ErrorPage.aspx"); 的东西

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

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

    【讨论】:

    • 这就是我的应用程序的做法,它对 99% 的错误都非常有效。但是今天我遇到了一个在渲染步骤中发生的异常。如果您在页面呈现一半之后Server.Transfer,那么您传输到的页面的 HTML 将简单地连接到已经呈现的任何内容。因此,您最终可能会看到半个损坏的页面,然后是下面的错误页面。
    • 由于某种原因,调用 Server.Transfer() 会导致问题并且根本不会显示错误。因此,我不建议使用这种方法。只需使用上面建议的 web.config 行(),它就可以正常工作
    【解决方案5】:

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

    【讨论】:

    • 就我而言,我只想要后端使用的异常信息,但这是个好建议。
    • 不回答问题。
    【解决方案6】:

    这是我的解决方案..

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

    【讨论】:

    • 这看起来不错,我正在尝试。因此,我为我的网页输入了错误的 url 以显示 404 并加载我的错误页面,但未检测到错误。我认为由于某种原因ServerGetLastError() 没有在 IIS 10 中获取任何内容。
    • 重定向到 ~/ErrorPages/Oops.aspx 对多个用户同时在 Web 应用程序中的多个错误有效?
    【解决方案7】:

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

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

    附:将数据存储在 Application 集合中而不先锁定再解锁是不安全的。

    【讨论】:

    • 只有在进行客户端重定向时才会出现这种情况。在进行服务器传输时,这都是一个请求的一部分,因此 application_error -> page_load 将全部发生在场中的一台服务器上,依次发生。
    【解决方案8】:

    它对我有用。在 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

    【讨论】:

      【解决方案9】:

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

      Session is null after ResponseRewrite

      Why is HttpContext.Session null when redirectMode = ResponseRewrite

      我试过并看到不需要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

      【讨论】:

      • 如果web有100个用户在线,同时抛出100个错误,不好用Application["TheException"]
      【解决方案10】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-24
        • 2014-06-27
        • 1970-01-01
        • 1970-01-01
        • 2016-11-26
        • 2013-06-08
        • 2011-07-10
        相关资源
        最近更新 更多