可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
回答1:
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.
回答2:
OK, I found this post:
http://msdn.microsoft.com/en-us/library/aa479319.aspx
with this very illustrative diagram:
diagram http://i.msdn.microsoft.com/Aa479319.customerrors_01(en-us,MSDN.10).gif
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.
回答3:
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 ...
}
回答4:
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.
回答5:
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.
回答6:
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.
回答7:
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;
}
}
回答8:
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
回答9:
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.
回答10:
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
And if an error occurs
As can be instead of displaying errors, variable \'log\' to be stored in the database
Source: Microsoft ASP.Net