Nov 22, 2011

Exceptional Extensions

I didn't fully embrace extensions when the were introduced, I'm finding out that was a mistake. I have started a small library with extensions for the string and exception classes. I'm sure as time goes on this library will grow. One of the things I like the most is how innocuous you can make them. You put them in your own namespace and they'll never bother anyone, but they can always come to your aid when summoned.

Recently I was working with Entity Framework and got a Validation Error. Finding out how to retrieve the actual errors was not intuitive and is exactly the kind of thing I immediately forget after I write it. Then I need it again in  a future project, so I either write a blog so I can remember or I go searching through Subversion. Now, when appropriate I can just add it to my extension library.  Inside my Syncor.Extensions.ExceptionExtensions class I recently added the following two extension methods (the first one was inspried by this answer at StackOverflow).

Two Exception Extension Method
  1. public static string GetAllValidationErrors (this List<DbEntityValidationResult> eveList)
  2. {
  3.     StringBuilder sb = new StringBuilder();
  4.     eveList.ForEach(eve=> sb.Append(eve.GetValidationErrors()) );
  5.     return sb.ToString();
  6. }
  7.  
  8. public static string GetValidationErrors(this DbEntityValidationResult eve)
  9. {           
  10.     StringBuilder sb = new StringBuilder();
  11.     string entity_msg = String.Format("Entity of type:{0}, in state:{1}, has the following validation errors:\n",
  12.                                eve.Entry.Entity.GetType().Name,
  13.                                eve.Entry.State);
  14.     sb.Append(entity_msg);
  15.     var err_msgs = eve.ValidationErrors.ToList().Select(ve =>
  16.         String.Format("  Property: {0}, Error: {1}\n", ve.PropertyName, ve.ErrorMessage));
  17.     err_msgs.ToList().ForEach(msg => sb.Append(msg));
  18.     return sb.ToString();
  19. }

You could easily make this one method if you wanted. I just find it more flexible and easier to understand when broken apart. Not only will I never forget how to do it, I won't need to remember, and the code that uses this is now pretty clean:

The clean catch
  1. catch (DbEntityValidationException ex)
  2. {
  3.     string full_msg = ex.EntityValidationErrors.ToList().GetAllValidationErrors();
  4.     RaiseError(full_msg);              
  5. }

Another useful exception extension is one that chains together the immediate extension message and any messages from inner extensions. It looks like this

Chain Inner Exception Messages
  1. public static string ChainExceptions( this Exception source)
  2. {
  3.     StringBuilder sb = new StringBuilder();
  4.  
  5.     while (source != null)
  6.     {
  7.         sb.AppendFormat("{0}\n", source.Message);
  8.         source = source.InnerException;
  9.     }
  10.     return sb.ToString();
  11. }

The use of this extension might look like:

Using ChainExceptions
  1. catch (Exception ex)
  2. {
  3.     var msg = String.Format("An error occurred while trying to save changes back to the database.\n{0}",
  4.                ex.ChainExceptions());
  5.     RaiseError(msg);
  6. }

About Me

My photo
Tod Gentille (@todgentille) is now a Curriculum Director for Pluralsight. He's been programming professionally since well before you were born and was a software consultant for most of his career. He's also a father, husband, drummer, and windsurfer. He wants to be a guitar player but he just hasn't got the chops for it.