Where to handle errors in BO's?

Where to handle errors in BO's?

Old forum URL: forums.lhotka.net/forums/t/7527.aspx


cdkisa posted on Friday, August 28, 2009

Just wondering which is the better place to handle errors if you want user friendly error messages to propagate to the UI:

1. Factory methods (i.e. Public Shared Function GetBO() As BO)
2. Data portal methods (i.e. DataPortal_Fetch)
3. Both?

Cheers

SonOfPirate replied on Sunday, August 30, 2009

My first question would be for you to define "error".  If you mean an exception that occurs while executing an operation, such as GetBO(), then don't handle it.  An exception is just that - an exception to normal operations - and you should let the exception bubble to the UI where the presentation layer/developer can decide how best to handle and display the message.

If you want to write the exception to the event log, or possibly wrap the exception in a new exception with a more descriptive message, always do that at the highest level possible in your code.  Throwing and handling exceptions is expensive, so they should never be used to implement business logic and you should always question any time you catch and re-throw the same exception.  In the latter case, unless you are adding value to the exception, just let it bubble up the call chain on its own.

So, given the choices you listed, you should include a try-catch block in your factory methods - if at all.

That said, there are times when exceptions occur at a lower level and we can handle them and prevent them from bubbling to the UI.  This is a different situation and we should always handle "expected" exceptions where we expect them to occur.  This should be rare, however, and hopefully there is an alternative way of coding the operation to prevent the expense of an exception.  A good example of this in the BCL is TryGetValue on a Dictionary.  Use this method rather than simply trying to get the object using the indexer property which will throw an exception if the item doesn't exist.

Hope that helps...

 

JonnyBee replied on Sunday, August 30, 2009

Hi,

I believe you should also consider exception handling from a layering perspective.

I do not want the UI to make decisions based on a low level DAL exception (Oracle/Teradata or my own custom DAL exception). In a multi tier environment I do not want the client to have additional dataproviders installed (or assemblies available) just for these exceptions.

So, as a general rule I prefer to define my own Exception base and throw my own Exception from DAL if  the Exception is not from a standard .Net assembly. Then my UI can make decisions on how to handle that type of Exception.

Remember also that there are som Exceptions that are non-serializable and Csla DataPortal does its best to extract info but eary versions of Csla may fail on these.

/jonnybee

cdkisa replied on Monday, August 31, 2009

Thanks for the replies. Sorry about the "Error Handling", old VB6 habbit.

They both address some fundamental flaws in my original thinking which was to handle the error (in some way) in each layer. This is because I want to log the original exception when it occurs to detect if I can correct it or at the least, log the exception. This, in my mind, would make the application more robust.

As for the CSLA version, I have been trying to keep that as up-to-date as possible.

Based on what both of you said, most (if not all) exception handling should be done at the UI level? Does that apply for web as well as PC?

tmg4340 replied on Monday, August 31, 2009

MS has actually put out some decent guidance on exception handling in .NET, so you might want to track it down.  The document is old, and a few things have changed since its inception, but the overall guidance is still largely relevant.  I point this out because these practices are .NET best practices, and will still serve you in CSLA as well.

Having said that, your "original thinking" still has some value.  The basic concept goes something like this: don't handle an exception unless you can do something about it.  But a lot depends on your definition of "handle".

There is nothing necessarily wrong with try/catch blocks at each layer of your app - data-access, business-logic, and UI.  However, unless you are actually in a position to recover from the exception (i.e. fix the problem and continue), the code in layers other than the UI generally does one or more of the following:

1. Log the exception.

2. Wrap the exception before re-throwing.

The logging reasons are obvious.  The wrapping reasons are because the "further away" from the exception you get in your app, the less it means.  For example, if you have a login page, and you throw an exception in your DAL because the user's data doesn't exist, it does no good to pass that database exception all the way up to the UI.  The database error doesn't really have anything to do with the actual login process, and in order to make the determination of whether you have a real issue or not (and what to display to the user), you have to do a lot of exception parsing.  Wrapping that database exception in some higher-level exception makes your UI easier to code, since you have less exceptions to consider, and those you do get are more contextual to the process at hand.

(Note that I'm not saying you should throw an exception in this instance.  Exceptions should not be used to manage application flow, and I don't really consider "no matching user information in the database" to be something... well, exceptional to the login process.)

Given these options, you generally only see exception handling at the "layer boundaries" - i.e. the public methods of your DAL/BLL.  How much you do depends on how much logging/wrapping you want to do.  Exception handling does carry a cost, so if you do a lot of it, you can affect the performance of your app.  But you won't really know how it affects performance until you benchmark it, so don't get too hung up on that.

Obviously, in your UI, it's a different story, since you're ultimately displaying something to the user.  And there's no real reason to wrap the exception, since there's nowhere else to re-throw it.  You certainly can log there, and many people do.  You'll probably have more exception handling in your UI than other layers, but I don't know as I'd call it "most".  Again, a lot depends on your exception-management strategy.

The other thing to consider is that there are some situations in .NET that rely on exceptions being thrown.  Transactions, for example, usually expect an exception to be thrown if there's a problem somewhere, so they know to do a rollback.  There aren't a lot of those, but they are out there, and if you don't play by the rules, you could get some unexpected behavior.

HTH

- Scott

JonnyBee replied on Monday, August 31, 2009

Hi,

If you use your own Csla baseclasses (as recommended from Rocky)  you could implement logging in these baseclasses (predefined methods called from DataPortal if they exists).

This way you will not have to implement logging in each class you define.

/jonnybee

cdkisa replied on Monday, August 31, 2009

Than you very much for your lengthy explanation!

I will take what you said and read the MS best practices doc and make my decision from there.

Cheers!

Copyright (c) Marimer LLC