Why Results Handlers are useful?

Shahar Shokrani
2 min readDec 6, 2020

--

I would like to demonstrate a good practice for handling results, through this simple snippet of code (validation if a user has been approved or not) :

public bool CheckIsApproved(int userId)
{
try
{
User user = this._userRepository.GetUserById(userId);
bool isApproved = user.IsApproved;
return isApproved;
}
catch (Exception ex)
{
_log.LogError(ex, “CheckIsApproved Failed”);
return false; // BAD!!!
}
}

Notice that in case of exception we returns false, and this method’s client could not tell whether or not it actual un-approved user or is exception has been thrown.

Another approach is to re-throw the exception again with:

public bool CheckIsApproved(int userId)
{
try
{
User user = this._userRepository.GetUserById(userId);
bool isApproved = user.IsApproved;
return isApproved;
}
catch (Exception ex)
{
_log.LogError(ex, “CheckIsApproved Failed”);
throw ex; // less bad!
}
}

This is actually a common practice but exceptions has down side in terms of performance in critical codes flow, and this method’s client should also handle exceptions instead of just focusing on logics.

For example in the case WEB API, the controller route that calls the service should look something like:

[HttpPost]
public IActionResult IsApproved(int userId)
{
bool result = this._usersService.CheckIsApproved(userId);
return Ok(result);
}

As you may see, the issue with returning true or false does not allow the route’s client to distinguish if something wrong had happened or if the user did not actually approve his email, the client always get Ok result (200) even in case of an exception within the userService.

In case of re-throwing the exception you can wrap the function with try-catch block:

[HttpPost]
public IActionResult IsApproved(int userId)
{
try
{
bool result = this._usersService.CheckIsApproved(userId);
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, ex.Message)
}
}

this approach has few down sides:

  1. What if you want send the clients a custom message instead of exception’s message regarding what happened within the service.
  2. It requires the parent to handle exceptions with try-catch block.
  3. No support for use case with results that involves more custom information that you want to share with the clients.

Result Handler to the rescue!

We can wrap the response signature with a static ResultHandler<T>:

inspirational credit to https://gist.github.com/vkhorikov/7852c7606f27c52bc288

public ResultHandler<bool> CheckIsApproved(int userId)
{
try
{
User user = this._dataAccess.Get<User>(userId);
if (user.IsBad)
return ResultHandler.Fail<bool>("Bad user not allowed");
return ResultHandler.Ok<bool>(user.IsApproved);
}
catch (Exception ex)
{
_log.LogError(ex, “CheckIsApproved Failed”);
return ResultHandler.Fail<bool>(ex);
}
}

And then the controller will know for sure to distinguish between failures and “real” false un-approved user, and can even tell the client side what exactly went wrong:

[HttpPost]
public IActionResult IsApproved(int id)
{
if (id == 0)
{
return BadRequest("id is zero");
}
var checkIsApprovedRH = this._usersService.CheckIsApproved(id);
if (checkIsApprovedRH.Success)
{
return Ok(checkIsApprovedRH.Value);
}
else
{
return StatusCode(500, checkIsApprovedRH.Message);
}
}

Here is a link to the ResultHandler class with some modifications.

--

--