First, I'm already familiar with the simple exception handling syntax but I'm asking about the best place, the best time and the best way to deal with them.
I'm building an N-Layered application. so I think the DAL will sometime generate some errors to handle .. and I just learned about the SqlException class, what's the deal with that class ? I once saw a code that handles the SqlException then it handles Exception!
After knowing the practice and where I'm going to handle them, I'm planning to create a method to connect to the database and log the errors in a database so I could fix it but still I don't know what information should I collect to allow me identify the whole situation!
I thought exceptions handling was not a big deal. but every now and then I read some strange advices -that I never understood- on the questions comments but no one could answer me since it was some very old questions!
"Don't just explicitly catch exceptions"
"the code that is used by higher-layers in your application must always only throw exceptions and never worry about how to deal with them."
EDIT
What about Page_Error
event and Application_Error
.. I saw that they are a good practice for handling errors
The how/when/where to catch exceptions may depend on what your trying to do exactly, its difficult to give an exact catch all always correct answer.
As to your specific questions,
Its good practice to handle the specific exception you believe may occur, if your not sure what type this exception is you can just 'Exception', if you want something specific to occur on a 'SQLException' and something else to happen with an 'Exception' then there is certainly nothing wrong with writing code that handles both.
I believe this is refering to code like this
This exception will be caught but you'll never know it happened, hence this is not a good idea, and the person using the code will be scratching their head as to whats going on.
IMO apart from extremely rare circumstances I only ever use exception handling for I/O related code where there are interactions with services and file systems whose functionality and maintenance is beyond the control of my applications.
I have always considered the use try/catch statements to manipulate the logic (flow-of-control) in a program in the same way if/else statement work to be extremely bad practice. Most common exceptions can be avoided if you use the tools at hand correctly.
Exception handling is a big deal, and it's not simple to design a good strategy for that.
First of all, some general rules:
For the third point, it's important to log exceptions and periodically analyse logs to find any weird situation. So, let's begin with the concrete answer.
First of all
think about "handling" the exception. When you write every single code line, think about the possible problems that may prevent it from completing, and think about the possible corrective actions. if any are possible. An error message is not a good handling way, it's the latest strategy.
Don't start to write try-catch(Exception), but prefer specific exceptions. If you need to parse strings to numbers etc, then expect
FormatException
, if you need to cast fromObject
to your type expectInvalidCastException
When you write lower-level layers
don't hesitate to throw exceptions!! Don't do like many folks do, ie.
return null
or use (like ANSI C) a boolean return value and reference parameters. Exceptions are there for that. If you can handle an exception (ie. you don't find a local file but you know you have a remote backup, so handleFileNotFoundException
by calling the remote mirror, but if you can't still connect then ultimately throw) then do it and try to resume computation, but if you cannot then throw. And don't forget to throw the inner exception, if present, because it is helpful for logging in the highest layer.Basically, you can still decide to throw an exception on your own even if you don't catch any! And this is highly recommended especially when function parameters are invalid!
Another good option is to still log in the underlying layers. You actually want to log no matter an exception occurs.
When you log
remember to give an adequate severity to the messages. If you find via code that your DB is offline, that's not an unexpected exception. Still log it as an error, but don't worry about code bugs when you investigate the logs. Instead, if you catch an exception that your code is unable to recognize (a
NullReferenceException
is a classic example) then log with highest severity, ie. fatal, to give it maximum priority!A good strategy for ASP.NET
can surely be based upon
Page.OnError
method. If you have a base page class for all of the pages of your site, you should definitely override that method. In that method, you should first log your exception.You also shouldn't abuse of try-catch(Exception) blocks, because if you don't catch an exception you can't handle with catch, you will have to handle it via OnError.
When you run such a method, don't immediately think about
Server.RemoveError()
. You can prefer to have a static HTML page for HTTP 500 error (that is triggered when an unhandled exception bubbles to ASP.NET runtime) that displays a courtesy message to the user.Briefly
throw
in underlying layers if anything strange occursOnError
, orApplication_Error
as single central point to handle all unexpected exceptionsI think what you are asking here is a Error/Exception Handling Strategy for any application.
I think it includes:
Where - All places where you think an exception can occur or which need more monitoring like DB calls, External Service Calls, Use of Arrays, User Input Parsing, Type Casting and so on...
How - All you high level layers should throw the exception and it should be captured at the entry point and processed to understand the root cause. Usually you do this in Application_Error() where you catch the exception and log it for troubleshooting. How you log an exception is upto you. A Log File or DB driven log is an option based on your requirements and available resources.
Take a look at elmah. It's a logger for asp.net. Renders all errors on a nice summary page.
http://code.google.com/p/elmah/
The best way to handle exceptions is in the specific layer they apply to. If it is a constraint volation, for example, 2 users with the same name, you should let that bubble up to the UI and alert the user.
Same goes with any business rule violations. Those should bubble up to the UI so the end user knows what went wrong.
A SQL Connectivity error is best handled in the DAL...etc..