views:

79

answers:

4

I am not sure where the best location to handle my exceptions in my DAL class. I have some code that does a read, and populates a list of business objects like the pseudo-code below:

public List<MyObject> GetMyObjects()
{          
  while (dataReader.Read()
  {
      try
      {
        //populate business object    
      }
      catch
      {
        //log exception?
      }
  }
}

The question I have is that I'm not sure if my logging class should be in this class, but throwing an exception isn't acceptable since it will cause the code to exit this method. What have the rest of you done in this situation?

NOTE: Per our business rules, the objects that cannot be loaded properly just need to be logged (this is due to some issues we are resolving in the database at the same time this code is being refactored).

+2  A: 

General rule of exception handling: Only catch and suppress the exception if you can do something about it, and if you can do something about it, there's no reason to log it :)

You can catch it in order to log it if that's what you want to do, but if that's the only reason, you must rethrow it afterwards.

Now ask yourself this question: Do I care about exceptions only in my DAL class, or do I care about exceptions in general?

Personally, I don't much care about where the exception was thrown when it comes to logging it. What I do care about is that it gets logged at all, so instead of baking in exception handling in particular classes, I deal with it in a general way.

Exception Handling is a Cross-Cutting Concern and should be treated as such. In other words, it's much better to have a general purpose exception handler/logger for the entire application. Here's an example of what I mean.

Mark Seemann
Can you explain this rule or link to more in-depth explanation? I am curious about it, because in the particular case I'm dealing with it would cause the system to become unstable (this is for an updater application, so I can't prompt the user to try different input or anything of that nature).
Blake Blackwell
are you only referring to logging the exception? while this may be true for web MVC frameworks, in many apps you would care the world about WHERE the exception was thrown... you may want to roll back changes etc.
Yonatan Karni
@Blakewell: This is a common misconception of .NET exception handling, but the converse is true: suppressing ALL exceptions will cause the system to become unstable. The following link is a good place to start: http://blogs.msdn.com/fxcop/archive/2006/06/14/FAQ_3A00_-Why-does-FxCop-warn-against-catch_2800_Exception_29003F00_-_2D00_-Part-1-_5B00_Nick-Guerrera_5D00_.aspx
Mark Seemann
@Yonatan Karni: You would care for specific exceptions because you would be able to do something about them, but not for general exceptions. There's not a whole lot you can do about an OutOfMemoryException.
Mark Seemann
Good discussion guys! I will see what we can do instead of suppressing exceptions, as I agree with Mark that this ultimately leads to a more unstable program/environment.
Blake Blackwell
@Blakewell: Just to be clear: there's nothing wrong with suppressing specific exception types. The point is that you should only do it if you know how to deal with it. In your case (where you want the process to continue) you could consider collecting all the exception messages for known/expected exception and raise them as events.
Mark Seemann
+2  A: 

Typically, I would say that the DAL is the wrong place to be handling exceptions. I would expect the caller to properly handle them. With your requirements as per your note...I don't think you have much choice.

My suggestion would be that, if you have to handle Exceptions in the DAL, modify the method slightly to allow the caller to inject a Logging framework into the method so that you're DAL isn't concerned with what Logging tool is being used:

public List<MyObject> GetMyObjects(ILogger logger)
{
    while(dataReader.Read())
    {
        try
        {
            // Do Stuff
        }
        catch(Exception ex)
        {
            logger.Log(ex.Message);
        }
    }
}

It'll make the code look a little more complicated, but this method insures that your DAL isn't tightly coupled to a single Logging Framework.

Justin Niessner
-1 This code supresses all exceptions - a very dangerous thing to do. I question the OP's requirement that the code must not throw. I've seen this requirement stated so many times in my career, and it's always wrong (based on incorrect assumptions on how .NET exceptions work).
Mark Seemann
@Mark - I understand that this supresses all exceptions...BUT this meets the OPs requirements. I specifically state that under normal conditions, this is not something you would want to do.
Justin Niessner
@Justin Niessner: Yes, I understand that, but as guides we should tell the OP that the requirement is wrong. If someone asks how to commit suicide, I wouldn't answer even if I technically could provide a correct answer.
Mark Seemann
A: 

Putting logging calls in your DAL is quite normal.

As long as your logging code doesn't actually use the DAL.

I would recommend using a logging framework such as Log4Net.

Joe R
Thanks Joe! Good to know this isn't unusual. I'm using NLog for my logging framework, so this should work well.
Blake Blackwell
Ok, good stuff.
Joe R
A: 

One of the reasons I like to do logging in the DAL is that you have a lot of useful data present about the error and the context. For example, you have the connection string, the name of the stored procedure called or the text of the SQL that was run. You can add all of that information to the log record. If you let the exception bubble up through the code layers, some of this data will no longer be available.

I would still rethrow the exception so that the appropriate layer(s) can either handle it or degrade gracefully.

DOK