Exception Management in N-Tier architecture

Hi,

The following are the layers in our application:

1. Entities/Collections
2. Data Access
3. Business Logic
4. Service Facade layer
5. UI

The way we implement our exception handling in each layer is :

1. Catch exception
2. Wrap the exception using a Custom Application Excpetion class, that also indicates the type of exception, say the exception is due to Data/Service or a Generic one.
3. Log the exception
4. Re-throw the exception to the next layer

Finally, in the UI Layer, a custom error page is shown indicating that an exception was raised.

We took this article as reference for handling exceptions:
http://msdn.microsoft.com/library/en-us/dnbda/html/exceptdotnet.asp

However, is there any other way the exception handling could be done other than rethrowing exceptions from layer to layer

We had an external comment saying that exceptions could be passed as ref parameter along with the methods.

Is this a better way than rethrowing exceptions across layers




Answer this question

Exception Management in N-Tier architecture

  • Masud Moshtaghi

    It's probably not suprising that I also favor the first solution. Don't lose any sleep over losing the stack trace, if you are running it all in process you'll have the standard .NET stack trace to view. What you may be missing are the detailed parameter values used to call that method that caused the failure. It shouldn't be hard to build your own exception class that wraps the base .NET exception type and collects method info information in memory and then uses that to log when an error occurs.

    IMO, putting try/catch in every layer is expensive and often overkill. Of course the N-Tier model does sort of put an interesting wrinkle in there but I'm not sure that's an architecture pattern that is cost effective.



  • DasFox

    Wow, I can't imagine catching and rethrowing an exception at every layer. This certainly sounds like an expensive approach ... what is it that you are buying by doing this In my experience exceptions can be caught at the process boundaries. For examle if you're ServiceFacade is implemented using one of the distributed technologies (asmx, remoting, entserv) then you'll want to catch, log and rethrow there.

    What I'm trying to say is why don't you just allow the errors to "bubble-up" to the edges I would likely have used throw BusinessException code in my entities when I encounter a business rule violation but I would only catch these (along with all other errors) at the services facade and the UI.

    There are a couple of justifications for handling errors this way, one would be that you are physically seperating your layers on distinct tiers (ouch!). Another might be that you want to do something special like build up all of the paramemters passed to the method so when it fails you can have some more meaningful information for debugging the problem at runtime.

    Hope this helps, if you'd like me to dive into a little more detail let me know.



  • SameerVartak

    IMHO, The second option assumes that exceptions will happen every time you will call a function, which is not the way you are supposed to think of exceptions. As their name implies, exceptions should be regarded as things that will happen in exceptional cases only, so it is not supposed to be passed with every method. Also this makes the responsibility of the CALLING method to handle the exception caused by the CALLED function, but doesn't make it obligatory to do so, so programmers may ignore or forget this step.

    in some way, the second solution is similar to the old return values, where Every method that may cause an exception can return an int indicating whether an exception took place or not, and what is the type of this exception.Loging of the exception will be the responsibility of the method at which the exception took place.

    If you are sure that the developers will check the return value - or the returned ref exception- then you can use this solution, but I don't recommend it.

    I think also that the third option contains a performance overhead due to catching and rethrowing the exception multiple times, as said before.

    I think the first solution is the best one for this situation.



  • PGolini

    Don't you love 'Industry Best Standards' ;)

    Mr. SOAP is right. But if you do this you're building a 2-Tier, 3-Tier, 4-Tier ... system, not an N-Tier one.

    The reason to throw and catch exceptions at each layer is to provide encaptulation and polymorphism of the layer, which allows for a more flexible distributed system.

    Also in true N-tier each layer should only have awareness (reference to) the layer below it for the same reason (this provides inheritance), so it does not assume that a layer above it can, or has, impemented an exception handler.

    Like Mr SOAP said this only counts in the real world if your layers are (or will be) on distinct tiers; and comes with a run time cost, however this is an ever increasingly popular requirement, so be careful.


  • Shargon

    I would tend to go with your option 3 as a general guideline -

    1. Not to bubble the exception across process boundaries - esp. across service boundaries (see also http://www.rgoarchitects.com/blog/PermaLink,guid,4465b3a8-fa80-42e8-a70b-25455b29a53f.aspx)

    2. don't just try - catch - throw. If you can't do anything with the exception and handle it let it bubble up

    3. Regarding the speed issue - if you have situations which are exceptions are more likely you can add a test method (e.g. if exists(whatever) .. PerformAction()) or add a variant that can return a true/false for success (as in void PerformAction() and bool TryAction())

    Arnon



  • johnvarney

    Hi,

    Thanks for the replies.

    In our case, the Entities/Collections, DAL, Business Logic and Service Facade will be on one machine, while the UI will be on a different machine.

    And we also follow the strategy that Wraps and Logs Exceptions at the place where they are found.

    With these considerations, what is the best approach that could be followed
    To sum up, these are the options that I have now:

    1. Let the exceptions bubble up till the Service Facade.
    - So in this case the exceptions will remain uncaught till the Facade layer, due to which we may not have the entire stack trace.
    And the Wrapping and Logging of exceptions will primarily happen only in the Facade.

    2. Instead of Re-throwing, have the exception as a ref parameter, with each method.
    - I suppose this would definitely be an overhead if every method in all layers have an extra ref paramether tagged.

    3. Re-throw across layers.
    - The one that was suggested in MSDN documentation.

    Please do let me know which is the best approach in our case.

    Thanks.



  • Exception Management in N-Tier architecture