What is the preferred method for handling exceptions in ASP.NET Webforms?
You have the Page_Error method that you add (I think) at web.config level, and the entire site gets redirected there when an error occurs.
Does that mean you shouldn't use try-catch anywhere in a webforms application? (Assuming you don't want to hide any errors)
Only catch the errors you can handle. If you can handle them in a manner that allows the page to continue loading then do so. Any other exception that would wreck the page should not be handled in any control or page as you would not be able to do anything anyways. Let it go to the global.asax handler and make sure you log the exception.
In addition to Andrew's suggestion, make sure to update the web.config file to set CustomErrors to "On" and specify a generic error page to redirect these top level errors. Global_asax will still log the error, and then the user can see a friendly page. It will also allow you to configure a few of the standard type errors, such as 404s and 200s, plus much more.
Web Application will normally consists of UI, Business and Data access layer.Each layer must do its part regarding exception handling. Each layer must (for code re usability) check for error condition and wrap exception(after logging it) and maybe propagated to the calling layer. The UI layer should hide exception and display a friendly message. Catching all exception in UI maybe not a good idea. Exceptions if possible should be logged in Database. This will allow ease of maintainence and correction of bugs
Avoid catching exceptions as far as possible. Try and validate all inputs before you use them. Rigorously validation( both client and server side) inputs with help of validation controls, custom controls and regular expression is a must.
string fname = "abc";
//Always check for condition, like file exists etc...
if (System.IO.File.Exists(fname))
{
}
else
{
}
Always make sure clean up code is called. Using statement or try finally.
You can catch all exceptions in Global.asax (asp.net application file)
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Exception objErr = Server.GetLastError().GetBaseException();
string err = "Error Caught in Application_Error event\n" +
"Error in: " + Request.Url.ToString() +
"\nError Message:" + objErr.Message.ToString()+
"\nStack Trace:" + objErr.StackTrace.ToString();
EventLog.WriteEntry("Sample_WebApp",err,EventLogEntryType.Error);
Server.ClearError();
//additional actions...
}
and add <customerror> section in your web config to redirect user to a separate page
<customErrors defaultRedirect="error.htm" mode="On">
</customErrors>
Useful links
MSDN
MSDN
Exception Logging- Peter Bromberg
You should use try/catch in places where you can do something meaningful with error, like fixing it or taking a different approach.
For all other cases you should use global try/catch using web.config custom errors page or Application_Error event to log the error and possibly to show it to the user.
If you use validation controls or check and validate user input in your code behind that will go a long way to preventing errors. I do recommend having a generic error page that can log the error for you. In cases where you are unsure of what will happen i suggest catching the error and handling it if at all possible and work on finding a way to know that what you are going to run will work before doing it.
Do you have a specific example in mind of where you might expect to encounter an error of this sort. One that I know of is when a session expires and you can no longer process the page. I check for this on every page load before anything else is run and then redirect the user if this has occurred.
Related
I am having a huge website with over 100 single sites in ASP.Net.
Of course I try to catch every action with a try-catch block or with other things like validation-controls.
But I want, IF a error happens which I get not catched to happens following:
1) Write the Error in Database
2) Show user a specific site instead the errorsite from asp.net
How to do that?
You can use the Application_Error event handler in in Global.asx to handle any exceptions that are not caught at the page level. See, for example,
http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
It's kind of up to you what you do in the event handler, so you can log the error to a database if you want to. You can also redirect to another page of your choosing to display the error however you want.
Note that the Application_Error event will be raised for all uncaught exceptions, including Http exceptions (e.g. 404 Not found). You probably don't want to log those.
You should try ELMAH
Check out the blog post of Scott Hanselman on how to integrate it in asp.net website and make it work.
Below is the article from Scott Mitchel on how to log errors with Elmah and how to show custom error page to user:
http://www.asp.net/web-forms/tutorials/deployment/deploying-web-site-projects/logging-error-details-with-elmah-cs
http://www.asp.net/web-forms/tutorials/deployment/deploying-web-site-projects/displaying-a-custom-error-page-cs
If you not into trying elmah, which is a breeze to setup. It depends on how your 100 sites are setup. But you possibly could look into using the global
Application_Error event in global.asax.cs and add you own handling code in there.
protected void Application_Error(object sender, EventArgs e)
{
var lastException = Server.GetLastError();
//log it to db, re-route the request to an alternate location ... etc
}
Another option, again it depends on how your sites are setup/hosted would be to read the event_log on the server, and check for ASP.NET errors saving the relevant details to the db.
I am using .net framework 4.0, plain asp.net and working with webform. Currently I having a base class to handle all parameter passing and redirect. I wonder is it possible to write a base class to handle nullRefeerenceException from all pages in once, lets say redirect end user to somewhere or display particular error message.
Scenario: For example, some pages must come along with parameter, if no parameter captured, I would like to redirect them to somewhere.
You can try to control the ProcessRequest. You need to test it to see if can do the work you ask for, but this is a good point to capture all errors of your page.
public override void ProcessRequest(HttpContext context)
{
try
{
base.ProcessRequest(context);
}
catch (Exception x)
{
// handle here your error from the page...
}
}
Some more notes
I was use this code on one critical page, but I do not use it for all my page. Even tho can capture the errors, some times you can not do nothing else here other than throw again the final error, so end up that is better to log your unknown and unhandled errors from globa.asax Application_Error, and on page make sure that you use try/catch to handle them where they happens.
After some think maybe is not good practice to use it. Good practice is to use try/catch in the place that you may have throws and not a general one like that.
Last
You also get throw error here when the user close the connection before the end of the render, but if you log the errors you get the same on Application_Error - this is not a page error.
Exception of type 'System.Web.HttpUnhandledException' was thrown. --->
System.Web.HttpException: The remote host closed the connection.
The error code is 0x80072746.
In you Global.asax, handle Application_Error.
When a NullReferenceException is handled by the server a 500 response is created. Redirect all of your server 500 messages however you want. This guide will help.
Definitive Guide to Handling 500 Errors in IIS6, IIS7, ASP.NET MVC3 with Custom Page
You can hook up to every uncatched NullReference Exception, depending on what you want to do.
For instance you can use the global.asax, to be specific the Application_Error Event. You can get a reference to the exception, look for the type and perform a redirect there.
Another way to get ahold of exceptions would be to write your custom error provider, but that wouldn't give you the possibility to perform a redirect.
As is suggested elsewhere, I am using redirectMode = ResponseRewrite in my custom error configuration so my custom error page can access the exception info. This has worked like a charm for some time.
In adding some more "help the user recover from an error" type functionality, we need a piece of info that has been previously stored in Session. When implementing this, I found that the various avenues to Session end in null when redirectMode=ResponseRewrite, but they are all populated when redirectMode=ResponseRedirect (or isn't defined).
Anyone know why? It seems odd that we'd have to choose between having exception info (ResponseRewrite) or having Session (ResponseRedirect).
The MSDN article on Rich Custom Error handling tells me that Session is only available when the control passing method is Server.Transfer, which is what I assumed ResponseRewrite used under the hood. Evidently that isn't the case.
I don't know the answer to the question yet, but to get past it, I took the redirectMode attribute out of my web config and put custom logic in the Global.asax Application_Error handler to do what I wanted. I am replacing the exception with a "user friendly" message exception, but essentially the transfer logic is:
if(Context.IsCustomErrorEnabled)
{
Server.Transfer("~/Error.aspx");
}
Then the Error.aspx page has Page_Load code to pull the error out of context and display the message.
In the Page_Load() section, I check for valid inputs & incase they are invalid, I transfer the request to a custom error page.
While doing so, a ThreadAbortException is thrown which is caught by my catch block but asp.net transfers the request to unknown exception page.
What am I doing wrong? I dont want the ThreadAbortException to come when I transfer to the error page.
eg:
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (String.IsNullOrEmpty(szProductName))
{
//Product name not given. Hence cant process further.
Server.Transfer(Constants.ERROR_WRONG_INPUTS_ASPX);
}
else
{
//Do something.....
}
}
catch(Exception Ex)
{
}
}
As a workaround, I now use:
Response.Redirect(Constants.ERROR_WRONG_INPUTS_ASPX, false);
instead of Server.Transfer i.e. I allow the process to continue in the background which made required I check for validity & then only executed the remaining code.
My problem is similar to : Exception Handling Application Block Exception Handler running in ASP.NET cannot call Response.End() but it seems it was not answered.
Response.Redirect throws the ThreadAbortException to abort the current page and transfer control to the new page. Adding the false parameter "fixed" this problem because it tells Response.Redirect to complete processing on the current page before transfering control.
I believe though you need to look at your application flow. Having a page transfer to an error page because of input errors seems like an overly complicated way to handle input validation to me. I think you are better off with a postback that displays messages, or doing some validation in javascript before the page is posted.
Any time that Response.End() is called, a ThreadAbortException will occur. Server.Transfer calls Response.End() internally because it immediately ends the current processing and hands off the request to the new page, which becomes responsible for returning information to the browser.
Response.Redirect is more graceful, as it finishes processing the current request and returns a 301 Redirect response to the client. Generally this causes the browser to do a second request to the server to request the redirect URL.
You say it's transferring to an unknown error page, but I'm not sure why. Are you doing so in your Application_Error method in Global.asax? If the error is handled you should be able to control where it's heading off to.
I sugest you get rid of that try...catch block. What are you expecting to catch out there? If you really expect some exceptional situation that depends on your implementation, that would happen further down inside your else block. So you should wrap it with try...finally there.
ASP.NET throws the ThreadAbortException when ending your request but it catches it eventually upper in the call stack so you should not catch that yourself. If you're expecting some other possible state corruption just let it propagate up to the global exception handler; it's not your code that throws.
If a product is missing or if the product isn't in your data store then you might want to consider returning a 404 (Page Not Found). This indicates to the browser - (and to google search spiders!) - that there isn't such a page. Are you planning on using SEO friendly URLS such as:
http://MyServer/MySite/Products/FireFox?
I am using ASP.Net 2.0. I found myself in an awkward situtation because I could not find the cause of an error. Up until now I have been using this idiom when it comes to accessing data.
try
{
access data
}
catch (SqlException exception)
{
Response.redirect("error.aspx");
}
finally
{
Dispose of connections, commands etc
}
Now I can never see what the actual error was because it is always handled. Sometimes I can run SQL Profiler and catch the last statement and run that in SQL Query Analyzer and see if there is a problem. That is obviously terrible.
So I thought that the global.asax Application_Error method would save me and I would email myself the exception. But this method seems to only be called for unhandled exceptions. So my question is, is rather better to not handle the exception at all, the system sends the email and use a customError page. Or is it better to ram the exception into the session, redirect to the error.aspx and try and do something with the error then. Is there a way to call Application_Error again? Because if I throw the exception again at the error.aspx then I get the yellow screen of death?
In my opinion, use a library (log4net for example) to log your exceptions and throw the exception again, let the asp.net redirect the error page to a custom page with web.config customErrors section.
Log4Net or Enterprise Library's Exception Handling Application Block both have email sending features.
Also take a look at ELMAH, very smart and pluggable exception handling module.
Logging would be invaluable here. In your catch blocks, log the error out to a log file. its a good idea to get in the habit of doing this at it can be a real life saver to see whats going on. Have a look at nlog which is a logging library. There are various tools out there too that allow you to analyse logs produced by nlog
Since you are using ASP.NET 2.0, your best bet is to do nothing.
ASP.NET added a feature called ASP.NET Health Monitoring. By default, this will log detailed exception information to the Application event log. It can be configured to send different kinds of problem to different destinations.
So, simply do nothing, and everything will be fine.
You can simply log the exception somewhere before redirecting to the Error page.
Something like :
try
{
//access data
}
catch (SqlException exception)
{
LogException(exception);
Response.redirect("error.aspx");
}
finally
{
//Dispose of connections, commands etc
}
Thus you can have it both ways, Customer will be directed to error page and still your exception is logged somewhere for you to review and get to the bottom of it.
By the way, there are many free logging libraries that you can use notably log4net and Enterprise library