Catching exceptions in service layer without hiding bugs

by FCin   Last Updated June 18, 2018 10:05 AM

Let's imagine we have a service CustomerService:

public class CustomerService
{
    public Customer GetCustomer(string customerName)
    {
        if(string.IsNullOrWhiteSpace(customerName))
            throw new ArgumentNullException(nameof(customerName));

        try
        {
            var customer = customerRepository.GetByName(customerName);
            return customer;
        }
        catch(Exception ex)
        {
            _logger.Error(ex);
            throw;
        }
    }
}

This service is used in a controller MyController:

public class MyController : Controller
{
     /* Properties */

     public ActionResult CustomerStuff(string customerName)
     {
          try
          {
              var customer = _customerService.GetCustomer(customerName);
              return View(customer);
          }
          catch (Exception ex)
          {
              // Redirect to error page, etc...
          }
     }
}

The problem with this is that I hide possible ArgumentNullException which is probably caused by a bug in my code. I never expect anything to pass null to GetCustomer, but catch(Exception) in MyController hides this exception with the rest of exceptions. On the other hand, on production I want to redirect users if something goes wrong in the CustomerService, because e.g. connection timeout occured.

How can this problem be resolved without tons of code, such as:

try
{

}
catch (Exception ex) when (!(ex is ArgumentNullException))
{
    // handle timeouts, network availability, etc..
}

One possible solution I can see is creating a custom exception, such as ServiceException and throwing it inside try/catch in GetCustomer method. Is there any other technique that is maybe more common?



Answers 1


Just change your service to:

public class CustomerService
{
    public Customer GetCustomer(string customerName)
    {
        try
        {
            if(string.IsNullOrWhiteSpace(customerName))
                throw new ArgumentNullException(nameof(customerName));

            var customer = customerRepository.GetByName(customerName);
            return customer;
        }
        catch(Exception ex)
        {
            _logger.Error(ex);
            throw;
        }
    }
}

That way, your logger catches the argument error, along with all other errors. The controller then needs no special logic to handle specific exceptions.

David Arno
David Arno
June 18, 2018 09:53 AM

Related Questions


Rethrow the same exception to provide more info

Updated April 06, 2015 23:02 PM


Extended usage of an exception

Updated April 19, 2015 21:02 PM

Why is there no 'finally' construct in C++?

Updated April 25, 2015 21:02 PM

How to write a good exception message

Updated May 17, 2015 19:02 PM