I'm using EF Core 2.0 with Repository and Unit of Work patterns. What is the best way to handle all db exceptions?. Can I just use try/catch in my commit method?
public void Commit()
{
try
{
_context.SaveChanges();
}
catch (Exception ex)
{
//code
}
}
Can anything beyond SaveChanges()
throw an exception? What should do next with caught exception?
I would give you an example how I would personally implement, maybe you can improve it as per your requirements but at least you have a good starting point.
Create a middleware which will handle exceptions in general like below:
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this._next = next;
}
public async Task Invoke(HttpContext context, ILogger logger)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, logger);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger)
{
if(exception is DbException)
{
//Do something else if needed
}
logger.Log(exception);
//do something
return context.Response.WriteAsync(... something ...); //Maybe some JSON message or something
}
}
Then register the middleware like below in configure method:
app.UseMiddleware<ErrorHandlingMiddleware>();
DbException
might be just a custom exception you may throw or you can put other existing exceptions types in there if you want to handle them differently.
In case you are using ASP.NET MVC you can have a BaseController
and use this here:
Second option I personally have used is by implementing unit of work like below.
using (var unitOfWork = UnitOfWorkManager.NewUnitOfWork()) { if (ModelState.IsValid) { //Do Stuff try { unitOfWork.Commit(); } catch (Exception e) { unitOfWork.Rollback(); LoggingService.LogCommitException(e); } } }
The second option is sometimes more preferable if you want to include more business logic code when an exception happened.
In your case go with second option but you may include both options in the solution as middleware can catch other global exceptions as well.
I would suggest to not include any try-catch
inside commit method because it is not it's responsibility to catch any exceptions, further more you would have to inject a logger inside of UnitOfWork
manager which can be emitted. So, to conclude commit
method has only to commit, other actions should be outside of its scope.