I am using mediatr to throw ValidationException once it finds errors, then in my API project I have a global exception handler that catches these and returns them to the caller, also it catches NotFound.
I feel like some of the code in my exception handler might be reduntant so I would like to make it as clean as possible.
I would like to achieve the following
Continue to use Mediatr to trap validation errors and throw ValidationException when it finds them
Wrap my responses so there is a "result" property when its successful (autowrapper does this already)
When there are validation errors, show them as a list (autowrapper does this but I couldnt get it to work with my code/global exception handler
for my NotFoundException (custom), return the message in the exception and return 404
Should I be throwing ApiException inside my globalexception handler? can global exception handler be completely removed and still be able to trap validation exception from mediatr and trap NotFound items and return a 404,
sorry for the confusion, I simple just want to add the functionality of AutoWrapper to my existing code to get the whole wrapping to my result, either good or bad returns
Global Exception Handler
public class HttpGlobalExceptionFilter : IExceptionFilter
{
private readonly IWebHostEnvironment _env;
private readonly ILogger<HttpGlobalExceptionFilter> _logger;
public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
{
_env = env;
_logger = logger;
}
public void OnException(ExceptionContext context)
{
var msg = context.Exception.Message;
switch (context.Exception)
{
case ValidationException ex:
{
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.StatusCode = (int) HttpStatusCode.BadRequest;
context.Result = new JsonResult(ex.Errors);
msg = string.Empty;
foreach (var error in ex.Errors)
msg += $"{error.ErrorMessage}: {error.AttemptedValue}" + Environment.NewLine;
break;
}
case NotFoundException:
msg = context.Exception.Message;
context.Result = new NotFoundError(context.Exception.Message);
context.HttpContext.Response.StatusCode = (int) HttpStatusCode.NotFound;
break;
default:
{
var json = new JsonErrorResponse
{
Messages = new[] {"An error occur.Try it again."}
};
if (_env.IsDevelopment()) json.DeveloperMessage = context.Exception.ToString();
context.Result = new InternalServerErrorObjectResult(json);
context.HttpContext.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
break;
}
}
_logger.LogError(new EventId(context.Exception.HResult), context.Exception, msg);
context.ExceptionHandled = true;
}
private class NotFoundError : ObjectResult
{
public NotFoundError(object error)
: base(error)
{
StatusCode = StatusCodes.Status404NotFound;
}
}
private class JsonErrorResponse
{
public string[] Messages { get; set; }
public string DeveloperMessage { get; set; }
}
public class InternalServerErrorObjectResult : ObjectResult
{
public InternalServerErrorObjectResult(object error)
: base(error)
{
StatusCode = StatusCodes.Status500InternalServerError;
}
}
}
Mediatr Validation Behaviour
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext<TRequest>(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0) throw new ValidationException(failures);
return next();
}
}
I am using mediatr to throw ValidationException once it finds errors, then in my API project I have a global exception handler that catches these and returns them to the caller, also it catches NotFound. I feel like some of the code in my exception handler might be reduntant so I would like to make it as clean as possible.
I would like to achieve the following
Should I be throwing ApiException inside my globalexception handler? can global exception handler be completely removed and still be able to trap validation exception from mediatr and trap NotFound items and return a 404,
sorry for the confusion, I simple just want to add the functionality of AutoWrapper to my existing code to get the whole wrapping to my result, either good or bad returns
Global Exception Handler
Mediatr Validation Behaviour