Reputation: 355
Was wondering what you thought of this solution, if this is right way to pass an error message to a custom page?
In web.config:
<customErrors mode="On" defaultRedirect="~/Error.aspx"></customErrors>
In Global.asax:
<script RunAt="server">
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex != null && Session != null)
{
ex.Data.Add("ErrorTime", DateTime.Now);
ex.Data.Add("ErrorSession", Session.SessionID);
HttpContext.Current.Cache["LastError"] = ex;
}
}
</script>
In my Error.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
if (HttpContext.Current.Cache["LastError"] != null)
{
Exception ex = (Exception)HttpContext.Current.Cache["LastError"];
if (ex.Data["ErrorTime"] != null && ex.Data["ErrorSession"] != null)
if ((DateTime)ex.Data["ErrorTime"] > DateTime.Now.AddSeconds(-30d) && ex.Data["ErrorSession"].ToString() == Session.SessionID)
Label1.Text = ex.InnerException.Message;
}
}
Of issue: I don't want to do a Server.Transfer from Global.asax because.. I don't know. Seemed clumsy to me. Want to be able to change customErrors to RemoteOnly. So have to save last exception somewhere, but can't be Session, so save to Cache but with some extra data (time and SessionID) since Cache is global and want to make sure not showing wrong error to someone.
I changed my code somewhat. Now it's just:
void Application_Error(object sender, EventArgs e)
{
HttpContext.Current.Cache["LastError"] = Server.GetLastError().GetBaseException();
Server.ClearError();
}
...and...
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
if (HttpContext.Current.Cache["LastError"] != null)
{
Exception ex = (Exception)HttpContext.Current.Cache["LastError"];
if (ex != null)
Label1.Text = ex.Message;
}
}
Note SessionID not there if anonymous user, and ex.Data.Add a key that's already there will cause error making me realize it's important to call ClearError
Upvotes: 4
Views: 8718
Reputation: 2736
GetLastError();
Keep in mind "This method is available only before the .asp file has sent any content to the client." - from MSDN doc
Upvotes: 0
Reputation: 211
I was in charge of creating a custom Error page. Everything was pretty simple: in the web.config file I had:
<customErrors mode="On">
<error statusCode="404" redirect="~/error-pages/page-not-found.aspx?error=1"
</customErrors>
and in Global.asax, in the Application_Error method: some code...
Server.Transfer("~/error-pages/error.aspx");
In the custom error page "error.aspx": Server.ClearError();
I don't know exactly what was modified, but this didn't worked anymore. When the code reached the Server.Transfer method, an exception was always raised: Error executing child request for the page...
I looked at some solutions and finally found this one. I modified my code, and now it seems to work:
<customErrors mode="On" defaultRedirect="~/error-pages/error.aspx">
<error statusCode="404" redirect="~/error-pages/page-not-found.aspx?error=1" />
</customErrors>
and in the global.asax method:
Session["LastError"] = Server.GetLastError();
It also worked with the Cache[""] code, but I prefered the Session variable.
So, thanks for the responses.
Hope this was usefull.
Upvotes: 0
Reputation: 3
Server.ClearError();
This line should be placed on Error.aspx.cs after displaying ErrorMessage I think.
Upvotes: 0
Reputation: 28865
I would have to agree with both n8wrl and Steve that a better approach would be to log errors in the database and then return just an Error ID to the user. They really don't need to see the technical details and it is possible that this will expose sensitive information.
In our case, we also pass in the user's ID (if available) and the page where the error occurred (Request.URL is still good when you get to the global Application_Error). This way, we can track down the error a bit easier. Note also that you don't have to use Global.asax with a script tag. If you create a Global.asax.cs file in your App_Code directory, you can just code your C# directly (this may depend on the project type, though).
Upvotes: 1
Reputation: 22220
I think that's a decent way to do it. It's not the way I do it, but my code is too lengthy to post (and in VB.NET).
One thing I would change is the error page itself. Instead of displaying the error, consider adding a textbox to the error page as an optional field where the user can enter their email address and click a button to send the error report to you. Then when you receive the error report you can look at the problem and reply to them. It's a much more user friendly way to do it and it's worked out quite well for the sites I've done this on.
Along those lines, you might also want to gather form data, session data, and anything else of value and put that into the error report as well. This can make diagnosing problems much easier.
Upvotes: 7
Reputation: 2278
As cache is global this wouldn't be advisable, as you've said you could be displaying the wrong error to someone. I should also say that you shouldn't output the error message directly to end users for security reasons.
Have a look at this issue:
ASP.NET custom error page server GetLastError is null
To summarise put something like the following:
Server.Transfer(String.Concat("~/Error.aspx?message=", HttpUtility.UrlEncode(ex.InnerException.Message)))
Rather than relying on ASP.NET to do the redirect using the settings in the CustomErrors section.
Upvotes: 1
Reputation: 19765
We do something that may or may not work for you. We do extensive logging in the DB. When we get an error, we log it and that produces an error ID. We redirect to the generic page with the error ID and get the details there.
of course this falls flat on its face when the error is 'cannot connect to DB' but that doesn't happen too often ;)
Upvotes: 1