What is the suggested approach or best practice for handling exceptions in tiered applications?
try/catch
blocks? Consider a simple example. Suppose you have a UI, that calls a business layer, that calls a data layer:
//UI protected void ButtonClick_GetObject(object sender, EventArgs e) { try { MyObj obj = Business.GetObj(); } catch (Exception ex) { Logger.Log(ex); //should the logging happen here, or at source? MessageBox.Show("An error occurred"); } } //Business public MyObj GetObj() { //is this try/catch block redundant? try { MyObj obj = DAL.GetObj(); } catch (Exception ex) { throw new Exception("A DAL Exception occurred", ex); } } //DAL public MyObj GetObj() { //Or is this try/catch block redundant? try { //connect to database, get object } catch (SqlException ex) { throw new Exception("A SQLException occurred", ex); } }
What criticisms would you make of the above exception handling?
thanks
Exception handling is the process of responding to unwanted or unexpected events when a computer program runs. Exception handling deals with these events to avoid the program or system crashing, and without this process, exceptions would disrupt the normal operation of a program.
NET Framework, an exception is an object that inherits from the System. Exception class. An exception is thrown from an area of code where a problem has occurred. The exception is passed up the call stack to a place where the application provides code to handle the exception.
And there are n-tier architecture models that have more than three tiers. Examples are applications that have these tiers: Services – such as print, directory, or database services. Business domain – the tier that would host Java, DCOM, CORBA, and other application server object.
My rule of thumb is generally to catch exceptions at the top level and log (or otherwise report) them there, because this is where you have the most information about the the error - most importantly the full stack trace.
There may be some reasons to catch exceptions in other tiers, however:
SqlException
wouldn't tell you.DatabaseUnavailableException
. The BL may ignore this for operations that are not critical or it may let it propogate for those that are. If the BL caught SqlException
instead it would be exposed to the implementation details of the DAL. Instead the possibility of throwing DatabaseUnavailableException
is part of the interface of the DAL.Logging the same error at multiple tiers is generally not useful, but I can think of one exception: when a lower tier doesn't know whether a problem is critical or not it can log it as a warning. If a higher tier decides that it is critical it can then log the same problem as an error.
Here are a few rules I follow related to exception handling:
Application.ThreadException
event should be implemented. In ASP .Net applications the Application_Error
event handler from global.asax should be implemented. These places are the upper most locations where you can catch exceptions in your code. In many applications this will be the place where you will catch most of the exceptions and besides logging, in here you will probably also implement a generic and friendly error message window that will be presented to the user. SqlConnection conn = null; try { conn = new SqlConnection(connString); ... } // do not implement any catch in here. db exceptions logic should be implemented at upper levels finally { // finalization code that should always be executed. if(conn != null) conn.Dispose(); }
throw;
. This will ensure that the stack trace is preserved. Using throw ex;
will reset the stack trace. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With