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

Posted

技术标签:

【中文标题】ASP.NET 自定义错误页面 - Server.GetLastError() 为空【英文标题】:ASP.NET custom error page - Server.GetLastError() is null 【发布时间】: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 添加“" 作为确认答案 【参考方案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 方法。

【讨论】:

以上是关于ASP.NET 自定义错误页面 - Server.GetLastError() 为空的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET自定义404和500错误页面

自定义 ASP.NET MVC 404 错误页面的路由

如何在 Asp.Net Mvc 3 中显示自定义错误页面?

旧 ASP.Net 应用程序中的自定义错误页面不起作用

asp.net MVC3 上的自定义错误页面

如何使自定义错误页面在 ASP.NET MVC 4 中工作