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?
Best Answer
Just change your service to:
That way, your logger catches the argument error, along with all other errors. The controller then needs no special logic to handle specific exceptions.