Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception handling in n-tier applications?

What is the suggested approach or best practice for handling exceptions in tiered applications?

  • Where should you place try/catch blocks?
  • Where should you implement logging?
  • Is there a suggested pattern for managing exceptions in n-tiered applications?

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

like image 976
flesh Avatar asked Nov 06 '10 13:11

flesh


People also ask

What is application of exception handling?

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.

What is exception handling in .NET framework?

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.

What are n-tier applications explain with suitable examples?

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.


2 Answers

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:

  1. The exception is actually handled. Eg. a connection failed, but the tier re-tries it.
  2. The exception is re-thrown with more information (that isn't already available from looking at the stack). Eg. the DAL might report which DB it was trying to connect to, which SqlException wouldn't tell you.
  3. The exception is translated into a more general exception that is part of the interface for that tier and may (or may not) be handled higher up. Eg. the DAL may catch connection errors and throw a 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.

like image 92
EMP Avatar answered Oct 01 '22 21:10

EMP


Here are a few rules I follow related to exception handling:

  • exceptions should only be caught in the layers that can implement the logic for handling them. Most of the cases this happens in the upmost layers. As a rule of thumb, before implementing a catch inside a layer, ask yourself if the logic of any of the upper layers depends in any way on the existence of the exception. For example in your business layer you might have the following rule: load data from an external service if the service is available, if not load it from the local cache. If calling the service throws an exption you can catch and log it at BL level and then return the data from the cache. The upper UI layer does not have to take any action in this case. However, if both the service and the cache call fail the exception would have to go to the UI level so that an error message can be displayed to the user.
  • all exceptions inside an application should be caught and if there is no special logic for handling them, they should be at least logged. Of course, this does not mean that you have to wrapp the code from all methods in try/catch blocks. Instead any application type has a global handler for uncaught exceptions. For example in Windows Applications the 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.
  • you can implement try/finally functionality where you need it without implementing a catch block. A catch block should not be implemented if you do not need to implement any exception handling logic. For example:
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(); } 
  • if you need to rethrow an exception from a catch block do that by simply using throw;. This will ensure that the stack trace is preserved. Using throw ex; will reset the stack trace.
  • if you need to rethrow an exception with another type that would make more sense for the upper levels, include the original exception in the InnerException property of the newly created exception.
  • if you need to throw exceptions from your code use meaningful exception types.
like image 22
Florin Dumitrescu Avatar answered Oct 01 '22 22:10

Florin Dumitrescu