Reputation: 45
is it possible to implement something similar to chain of responsibility pattern in .net core middleware which catches exceptions? Because I wanted to Handle exceptions globally and take them to their handlers. Example
try
{
}
catch(CustomException1 ex)
{
}
catch(CustomException2 ex)
{
}
...
The middleware grows really fast and it will be hard to maintain later. I wanted to try{} catch(Exception e) { Handle(e); }
and make Handlers for each Exception, for example handler for NullReference etc. I though about solution to take the exception by type and handle it in the handle() method in the specified handler.
Upvotes: 1
Views: 970
Reputation: 4303
I'm toying around with middleware, so in startup:
app.UseMiddleware<ErrorHandlingMiddleware>();
Middleware, I have one general exception handler, you could add many here (sample code, Sentry is an error log service...sentry.io):
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly IHub _sentry;
public ErrorHandlingMiddleware(RequestDelegate next, IHub sentry)
{
_sentry = sentry;
_next = next;
}
public async Task Invoke(HttpContext context/* other dependencies */)
{
try
{
await _next(context).ConfigureAwait(false);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex).ConfigureAwait(false);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = HttpStatusCode.InternalServerError; // 500 if unexpected
if (exception is ValueNotAcceptedException) code = HttpStatusCode.NotAcceptable;
/*if (exception is MyNotFoundException) code = HttpStatusCode.NotFound;
else if (exception is MyUnauthorizedException) code = HttpStatusCode.Unauthorized;
else if (exception is MyException) code = HttpStatusCode.BadRequest;*/
// send to Sentry.IO
_sentry.CaptureException(exception);
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
Note adding a dependency in the constructor will make it a singleton, last the life-cycle of the app (in my case it's fine), or else add dependency in the Invoke.
Upvotes: 2
Reputation: 2009
You can create multiple exception handler IExceptionFilter
. After create filters you can inject thats Mvc filters at startup.
Note: mvc filters get hit later than custom middleware.
Note: first added filter get hit last.
services.AddMvc(options =>
{
options.Filters.Add<GeneralExceptionFilter>();
options.Filters.Add<DbExceptionFilter>();
});
Note: if you decide filter should not handle exception, you should not throws exception. You should set ExceptionHandled
false
public void OnException(ExceptionContext context)
{
...
context.ExceptionHandled = false;
}
You can also create .net core middlewares and inject it from startup. Concepts are pretty similar to mvc filters.
Upvotes: 1