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 添加“仔细查看我的 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 相关,而不是共享错误页面请求。感谢您的指点,我错过了那个新功能! 这不适用于UpdatePanel
s 中的控件触发的异常;错误页面将不再显示。
因为它是一个旧答案,添加我的评论以证明重定向模式中的这个很好的 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 行(虽然这里有几个很好的答案,但我必须指出,在错误页面上显示系统异常消息并不是一个好习惯(我假设您想要这样做)。您可能会无意中向恶意用户透露您不希望这样做的内容。例如 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() 为空的主要内容,如果未能解决你的问题,请参考以下文章