Recommended Patterns

Some things are inevitable in life. The same is true in software development. One of those inevitable things in writing code is a system exception. The basic goal for handling exceptions in any software is to pick from 4 basic good patterns:

  • Handle
  • Wrap
  • Replace
  • Propagate

Whenever your code encounters a system error, it should take one of the above actions. Listed below are some design patterns for how to handle a .NET exception in your application.

Handle Pattern

The Handle pattern shows up most often in network transaction handling code where retries of some sort or another are normal and expected. When using this pattern, you must be diligent in avoiding blocking for long amounts of time.

private List<Widget> GetWidgets()

{

List<Widget> widgets = new List<Widget>();

try

{

//try fetching the widgets from the main server first.

widgets = DataAccess.GetWidgets(servers.Main);

}

catch (WidgetDatabaseUnavailableException offline)

{

//Let’s ‘handle’ this specific exception. In this example, we want to

//redirect to a secondary service or device.

//Make sure that we record the first failure.

Logger.Write(offline);

 

//try again with the alternate server cluster.

//If this attempt fails, then

//we truly have an unresolvable system failure.

//The exception will be raised to the client code.

widgets = DataAccess.GetWidgets(servers.FailOver);

}

//return our list, empty or not.

return widgets;

}

 

Wrap Pattern

The Wrap pattern is most commonly used to provide a more context sensible exception. The general pattern is to embed or ‘wrap’ the root exception, which may be way too verbose or technical, inside of a context specific user exception.

This allows the original exception to be accessed along with stack and trace information if it needs to be accessed. Here is how to define a ‘wrap-able’ user defined exception:

class WidgetDatabaseUnavailableException : Exception

{

public WidgetDatabaseUnavailableException(string msg,Exception x):base(msg,x)

{

}

 

public WidgetDatabaseUnavailableException()

: base()

{

}

}

 

And here is an example of a Wrap exception handling pattern:

private List<Widget> GetWidgetsWrap()

{

List<Widget> widgets = new List<Widget>();

try

{

widgets = DataAccess.GetWidgets(servers.Main);

}

catch (SqlException rootProblem)

{

//Let’s wrap this exception inside of another, more context

//specific exception.

WidgetDatabaseUnavailableException widgetException =

new WidgetDatabaseUnavailableException(

Properties.Resources.UnableToLoadWidgets,rootProblem);

 

//now throw our more specific exception along with detail information about

//the root cause of our problem, the SqlException problem. The complete

//stack trace is available in the inner exception to the UI code or other

//callers.

throw widgetException;

}

//return our list, empty or not.

return widgets;

}

 

Replace Pattern

The Replace pattern is often used to avoid exposing sensitive information, like credit card numbers and social security. It is a common pattern to replace the exception that contains sensitive information with one that has number masks or similar methods to protect customer or entity identity information from being displayed in user interfaces.

private void ChargeVisa(Charge customerCard)

{

try

{

//we are attempting to charge a customer's credit

//card. Because of Sarbanes-Oxley, we cannot display

//the customer's credit card number. If an exception

//occurs, then we will log the true exception, but

//pass a sanitized exception back to the UI.

BillingCenter.Charge(customerCard);

}

catch (CreditCardExpiredException expired)

{

//The customer's credit card did not work.

//Log the root cause of the problem (with specifics)

//to the system database.

Logger.Write(expired);

 

//Replace the original exception and pass a replacement

// back to the User Interface or other client code.

//The application can choose to retry the transaction and

//display sanitized customer card information to the user.

throw new BillingCenterException(customerCard.CardHolder,

customerCard.MaskedCardNumber, customerCard.Expiration, customerCard.Amount);

}

}

 

Propagate or ‘Bubble’

The propagate pattern targets one or more exceptions which are unconditionally thrown to the caller. However, the Propagate pattern may also be constructed to process any remaining exceptions with alternate courses of action. In the following example, we are going to retry fetching the widgets a second time as long as the database did not report ‘offline’.

private List<Widget> GetWidgetsPropagate()

{

List<Widget> widgets = new List<Widget>();

try

{

widgets = DataAccess.GetWidgets(servers.Main);

}

catch (WidgetDatabaseUnavailableException offline)

{

//Let’s ‘handle’ this specific exception. In this example,

//the widget database is offline. If the database is

//offline, there is no point in retrying. PROPOGATE this

//exception immediately upward to the caller.

throw;

}

catch (Exception allOtherExceptions)

{

//Let’s attempt to handle all other exceptions by retrying.

widgets = DataAccess.GetWidgets(servers.FailOver);

}

 

//return our list, empty or not.

return widgets;

}

 

 

Exception Handling Anti-patterns

In most cases, exception handling is relatively well defined. However, there are some anti-patterns that will cause red flags in code reviews. The most common errors are:

1.      Suppressing Exceptions

2.      Losing stack traces

3.      Failure to log exceptions correctly

4.      Wrapping and replacing exceptions out of context

5.       

Here are some examples of each anti-pattern and a couple of good patterns

Anti-pattern: Suppress

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50/zero;

}

catch (Exception exception)

{

//Very bad!!! I didn't do anything with the exception. The application has no

//idea that this caused a problem!

}

 

 

Anti-pattern: Suppress and Log

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50/zero;

}

catch (Exception exception)

{

//Very bad!!!. The client code has no

//idea that this caused a problem! To make it even worse, I

//will log the exception, but the application may exhibit

//strange behaviors as the exceptions pile up during runtime

Logger.Write(exception);

}

 

 

Anti-pattern: Suppress and Return false, 0, or null

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50/zero;

}

catch (Exception exception)

{

//don't do anything with the exception. The application has no

//idea that this caused a problem!

return false;

}

Anti-pattern: Losing Stack Trace

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50 / zero;

}

catch(Exception exception)

{

//uh oh! We don't know what really happened. We will lose

//all stack trace information in this case.

throw new Exception("My custom exception");

}

 

 

Anti-pattern: Log and Throw

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50 / zero;

}

catch(Exception exception)

{

//ok. We are going to log this error, but the problem is

//that the call may do the same thing – resulting in

//multiple error messages in the log of the same thing!

Logger.Write(exception);

throw ;

}

 

 

Anti-pattern: Wrap and Lose Stack

try

{

int x;

int zero = 0;

//this will cause a DivideByZeroException

x = 50 / zero;

}

catch(Exception exception)

{

//This is also quite bad. We lost the stack trace!

MyCustomException mine = new MyCustomException(“I had a bad attempt”, exception.Message);

throw mine;

}

 

 

 


Posted by: ezekiel.brooks
Posted on: 6/18/2009 at 2:54 PM
Tags:
Categories: C# | Mentoring
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed
 
 

Ok. So, after looking at C# 4.0, it has a lot of really cool features. But here, cool is not necessarily good. Am I hating on C# 4.0? Lol. Not at all. I love C#. It is a wonderful, strongly typed, 4th Generation OOPL. But around here, balance is the key. History is important unless you just have a burning desire to repeat past mistakes.

So, in the spirit of Meta { ! } Think, I want you to consider this possibility. Could it be that despite all of the really brilliant constructs in C# 4.0, we are actually creating more problems than solutions? Or is C# 4.0 really the best thing since sliced bread? Let's go back in time a bit for some perspective before we pass judgement.

And Before C#...

Way back when in the late nineties, Visual C++ was all the rage. We had been delivered from plain old C along with the millions of linearly constructed applications that went with it. We had OO concepts - classes, dynamic callbacks and such with C++. Yay!

However, C++ eventually became known as the 'Chainsaw' where I worked. Why? Quick and massive damage - just like with a real chainsaw. One mistake and you could lose a limb (or at least kill an entire app or system). C++ pretty much fit this profile - one small mistake with a pointer, casting, Interop, or COM would create a mushroom cloud in your app.

We had conditioned ourselves to expect fatal exceptions at any time. Testing cycles were very, very, long for C++ apps. God forbid if you were talking to COM or DCOM objects as well. This was early dynamic programming at its worst. 

Dynamic Programming in C#

So. here it is years later. C# has pretty much eliminated these sorts of heinous practices of old. It's object oriented, precise, and strongly typed all over the place. Sweet. But, the language has evolved with C# 4.0. The really bright people who write extensions to C# ( http://code.msdn.microsoft.com/csharpfuture)  have come up with Dynamic Lookup capabilities to allow integration with

  1. Ruby, Python and other dynamic languages
  2. COM IDispatch objects,
  3. Reflection-based dynamic programming,
  4. HTML DOM.

Sweet - if you *have* to talk to these sorts of objects in your systems.  But, if you don't have to, I wouldn't. I certainly wouldn't do it for the cool factor. I saw enough of 'Programmers Gone Wild' with C++ back in the day.  Before using the dynamic features of C# 4.0 without restraint, remember that the more external non-native modules (e.g. COM) that you couple into a solution, the more complex and unstable it tends to be.

We used to call C++/COM amalgams 'Frankenapps'. This is, of course, a play on words to bring to mind Frankenstein - you get the picture. Unfortunately, I see the potential to open that Pandora's box of issues up all over again with C# Dynamic Programming. I would advise anyone to ask the following questions of themselves before rushing to consume dynamic objects from other paradigms:

  • Can I solve this problem without exposing my statically typed C# application to a wild universe of variances, permutations, and dependencies in dynamic objects?
  • Will dynamic programming make this application more or less stable?.
  • Could I use SOA or other messaging techniques to communicate with the targeted dynamic objects or systems? 
  • Do I believe that binding to these dynamic objects will simplify or complicate my solution unnecessarily? 

 

This is easy in C# 4.0, but is it a good idea?

var xl = new Excel.Application();
xl.Cells[1, 1].Value2 = "Process Name";
xl.Cells[1, 2].Value2 = "Memory Usage";

Remember Frankenstein. Wink
 

 

 

 


Posted by: ezekiel.brooks
Posted on: 6/7/2009 at 7:21 PM
Tags:
Categories: C#
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed