I like to start by categorize the possible errors.
Categorize the errors.
- Page Not Found (this is full my log).
- Breaking parameters of the page by trying to hack it
- Error from wrong user data input.
- Totally Unknown error - a new bug that we must fix.
- a Very hard General error - nothing runs - eg, database is not opens at all.
Our Goal
To now show the error page, but only in rare cases.
So when user make actions with out page, we try to capture all wrong input of the user, and show him what to do to continue with out any error.
Global Error Handler
You can start by capture on global.asax
all errors using the void Application_Error(object sender, EventArgs e)
void Application_Error(object sender, EventArgs e)
{
try
{
Exception LastOneError = Server.GetLastError();
if (LastOneError != null)
{
Debug.Fail("Unhandled error: " + LastOneError.ToString());
if (!(EventLog.SourceExists(SourceName)))
EventLog.CreateEventSource(SourceName, LogName);
EventLog MyLog = new EventLog();
MyLog.Source = SourceName;
StringBuilder cReportMe = new StringBuilder();
cReportMe.Append("[Error come from ip:");
cReportMe.Append(GetRemoteHostIP());
cReportMe.Append("] ");
cReportMe.Append("Last Error:");
cReportMe.Append(LastOneError.ToString());
if (LastOneError.ToString().Contains("does not exist."))
{
// page not found
MyLog.WriteEntry(cReportMe.ToString(), EventLogEntryType.Warning, 998);
}
else
{
MyLog.WriteEntry(cReportMe.ToString(), EventLogEntryType.Error, 999);
}
}
}
catch (Exception ex)
{
Debug.Fail("Unhandled error: " + GlobalFun.GetErrorMessage(ex));
}
string cTheFile = HttpContext.Current.Request.Path;
// to avoid close loop and stackoverflow
if(!cTheFile.EndsWith("error.aspx"))
Server.Transfer("~/error.aspx");
}
This global error handle have one main goal, to tell me whats is not working and fail to handle it before reach here, so I log it (not manner the way of log it) and fix it soon. When I debug my code I did not make the server transfer to be able to locate the error fast.
For the hacking error case
In this case is better to now show any error but just reload the page by making a redirect. How to know if its trying to hack the page ?
If on post back you get some CRC/hach error of your parameters you know that. Look that answer https://stackoverflow.com/a/2551810/159270 to see an example of a viewstate error and how to handle it.
I know that MVC did not have viewstate, but you may have other encrypted string on your code, or some kind of security that you can know when its broken. This is the general idea:
if(IsPostBack && HashErrorOnParametres)
{
LogIt();
Responce.Redirect(Request.RawUrl, true);
return;
}
For a very hard General Error
Let say that your database is not open at all, then all users start to see the error page from the general handler. There you may have an extra option to restart the pool, or stop the pages after 20 errors in the last 5 minute, or something similar, and send you email to run and fix this very hard error.
For the rest soft errors
I think that all the possible known errors must be handled inside the page using try/catch and show to the user a message for what go wrong, if this error is from the user, and of course log it to see it and fix it.
Breaking the page in parts, maybe one part is throw the error and the rest working good, if this is not so important you can simple hide this part, and show the rest, until you fix it. For example if you just show information's about a product, and a part that speak about one part is throw an error, you can simple hide this part and see it on the log and fix it.
Some time I was try to handle the error per page, using protected override void OnError(EventArgs e)
but this is not help me, and I remove it. I handle the errors per action, and if they are not critical I hide them until I fix them.
The rest normal errors is shown on the user, eg is not entered the correct data... a message for that and tell them what to fix.
As I say, my goal is to not show the error page at all.