Before you run off and google, I have read lots of articles, posts, and comments on Exception handling, but I am still stuck on these specific points.
Given the example below how would you deal with the following scenarios?
- If an exception occurs in the DAL layer and is wrapped in a custom exception to provide more information and to better categorize it. How do I log it?
If I log it as it occurs in the DAL layer it will be logged again in the global handler (using elmah). I could let it propogate, but what happens if the ServiceLayer needs to translate that exception into a more user-friendly message for a user or possible for transactional purposes (think rollback)? I will lose information gathered in the DAL exception (the message anyway, not necessarily the stacktrace).
// UI
public static GetUser(int userId)
{
// Should I do validation here or in service layer
try
{
IUserService s = new UserService(userId);
s.GetUser(userId);
}
catch(ServiceLayerException ex)
{
// ex.Message displayed to user
}
}
// Service layer
public User GetUser(int userId)
{
try
{
return repo.GetUser(userId);
}
catch(DALException ex)
{
// user-friendly message displayed to user
throw new ServiceLayerException("User does not exist");
}
}
// DAL
public User GetUser(int userId)
{
try
{
// Query for user, if fails throw DALException
return userId;
}
catch (SqlException ex)
{
throw new DALException("Could not retrieve user with userId " + userId.ToString());
}
}
Personally I prefer to Log at the coalface – where the exception actually happened, so in the first case I would log in the DAL. The Bal (Service Layer) can handle the error if we do not want to propogate the error, or allow elmah to log it (which is not a bad thing as it will show on the error page and help with tracking the exception).
The service layer can also pass the DAL error as an inner exception so that it is accessable during/after propgation if required – and exception iteslf can be mutated as required between layers. The user will generally not want such info, and just receives the usual dumbed down message.
It is also possible to use events to collect exception data (with specialised event arguements) and just pass back boolean methods returns, this can be more controllable and tailorable – though this then puts the onus on you to propogate or not, and it is likely to only be used for “expected” exceptions.