The problem is, exception handling is quiet complicated code and is often highly redundant, what makes it awkward to keep it in sync.
The Common Approach For Exception Handling
As a simple sample, guess we are developing a web-service method that returns a Country object from data storage by a specified ISO 3-alpha.[OperationContract] public Country GetByIsoAlpha3_Simple(string alpha3) { Logger.Trace("Entered GetByIsoAlpha3"); try { ThrowHelper.CheckNullArg(alpha3); CountrySource source = new CountrySource(); return source.GetByIsoAlpha3(alpha3); } catch (ArgumentException ex) { throw new FaultException(ex.Message); } catch (DbException ex) { Logger.LogEx(ex); throw new FaultException("There was error with the data storage."); } catch (Exception ex) { Logger.LogEx(ex); throw new FaultException("A internal error occurred"); } finally { Logger.Trace("Leaving GetByIsoAlpha3"); } }
As we see, the real functionality is only two lines of code, the rest of the 25 lines are standard exception handling and the validation of the input values.
The problem with this method is, it's very dangerous remember all required tasks for standard exception handling. Does it handle all standard exceptions we usually handle? Might it be useful to log the ArgumentException? Do we really want to tell the caller that we had an error with the data storage? How can we ensure that all web methods do the same standard exception handling.
Extract The Exception Handling
A good way to ensure all standard exception handling is to move it out into a static helper class.static class WsHelper { public static T ExecuteWebMethod<T>(string methodName, Func<T> method) { Logger.Trace("Entered " + methodName); try { return method(); } catch (ArgumentException ex) { throw new FaultException(ex.Message); } catch (DbException ex) { Logger.LogEx(ex); throw new FaultException("There was error with the data storage."); } catch (Exception ex) { Logger.LogEx(ex); throw new FaultException("A internal error occurred"); } finally { Logger.Trace("Leaving " + methodName); } } }
Using Lambda Expressions To Utilize The Helper
Now, we can utilize the ExecuteWebMethod method with a simple Lambda expression.[OperationContract] public Country GetByIsoAlpha3_Lambda(string alpha3) { return WsHelper.ExecuteWebMethod("GetByIsoAlpha3_Lambda", () => { ThrowHelper.CheckNullArg(alpha3); CountrySource source = new CountrySource(); return source.GetByIsoAlpha3(alpha3); }); }As we see, the code of our web method is reduced to six lines. Still three lines for our method specific work, two lines with braces and one line calling the helper method which gets a Func<T> that represents the implementation of the web method.
Possible Extensions
The exceptions handled in this sample are only exemplary. If you have some other common standard exceptions like a ValidationException or a general BusinessException, feel free to extend the ExecuteWebMethod.For sure, you noticed the methodName parameter, provided for the ExecuteWebMethod operation. To get rid of this parameter we can use the StackTrace class to determine the calling method. In case of web services or other boundaries, this is a good approach. Nevertheless, be careful with StackTrace in highly utilized methods since stack trace evaluation is an expensive task.