We develop on a ASP.NET Web API where we use the "Unit Of Work / Repository" pattern :
Our Controllers looks like that :
public class MyController : Controller
{
private IUnitOfWork _unitOfWork;
private IMyService _myService;
public MyController(IUnitOfWork unitOfWork, IMyService myService)
{
_unitOfWork = unitOfWork;
_myService = myService;
}
[HttpPost]
public IActionResult CreateItem(Item item)
{
try
{
_unitOfWork.BeginTransaction();
_myService.CreateItem(item);
_unitOfWork.Commit();
}
catch (Exception e)
{
// Transaction failed, we must rollback to keep a consistent state
_unitOfWork.Rollback();
// Logging
//...
// Return HTTP 500 Error
return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError);
}
return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status200OK);
}
}
We will have multiple controller with the same logic :
- Start a transaction
- Do business logic
- Commit the changes
- Handle possible exceptions (Rollback, Log, return appropriate HTTP status)
So, we are wondering if we can "centralize" this code in order to avoid duplication
Only the business logic will differ
In this class :
_myService.CreateItem(item);
Is it really a good idea ?
And if yes what pattern would be the best ?
EDIT
After some more investigation it seems that the only thing we really need to centralize is the exception handling
In this case, we would have this kind of controllers :
public class MyController : Controller
{
private IUnitOfWork _unitOfWork;
private IMyService _myService;
public MyController(IUnitOfWork unitOfWork, IMyService myService)
{
_unitOfWork = unitOfWork;
_myService = myService;
}
[HttpPost]
public void CreateItem(Item item)
{
using (var uow = _unitOfWork.BeginTransaction())
{
_myService.CreateItem(item);
_unitOfWork.Commit();
}
}
}
The exception handling would be centralized with ExceptionFilter as explained here :
For the Rollback, it seems there is no need to handle it manually :
Best Answer
Of course you could move this code to some class that handles this for you, for example using the business logic as an Action (https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx) or something like that. This could definitely be a solution for the transaction management and probably for the HTTP 500 and 200 result codes.
Calling it from the Controller:
you may need to check the details about calling the Action, haven't tried this).
However, you will also need some error handling for specific situations. Any call to your WebAPI can have different situations when to return which HTTP error code like the 4xx's. Those checks will always be in the Controller itself.
Don't get tempted to return StatusCodes from your business logic.