Reputation: 511
We are using the CQRS pattern and we have a problem with fluent validation's error handling. (CQRS pattern @ https://lostechies.com/jimmybogard/2015/05/05/cqrs-with-mediatr-and-automapper/ )
public class OtherSpecified : AbstractValidator<Command>
{
public OtherSpecified(ApplicationDbContext context)
{
RuleFor(x => x.Other).NotNull();
}
}
public class DepartmentSpecified : AbstractValidator<Command>
{
public DepartmentSpecified(ApplicationDbContext context)
{
RuleFor(x => x.Department).NotNull();
}
}
Now we inject our validation handler so we can run multiple abstract validator based on info from http://lostechies.com/jimmybogard/2014/09/09/tackling-cross-cutting-concerns-with-a-mediator-pipeline/. This works but because I can see the rules running in the foreach loop
public TResponse Handle(TRequest request)
{
var context = new ValidationContext(request);
var result = new ValidationResult();
var list = _validators.ToList();
foreach (var validator in list)
{
var results = validator.Validate(request);
foreach (var validationFailure in results.Errors)
{
result.Errors.Add(validationFailure);
//temp testing code below
if (results.Errors.Count > 0)
throw new ValidationException(result.Errors);
}
}
if (result.Errors != null &&
result.Errors.Count > 0)
{
throw new ValidationException(result.Errors);
}
return _inner.Handle(request);
}
The problem is that the fluent validation exception ( ValidationException ) is not handled. The rule errors bubbles up as
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: FluentValidation.ValidationException: Validation failed:
What I would expect is Fluent validation to handle the error and pass it back to the ajax request in json as validation errors
Upvotes: 1
Views: 6718
Reputation: 511
I catch the ValidationExceptionwith an HandleErrorAttribute and return json to the ajax request.
public class ValidationExceptionHandlerErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
//only handle ValidationExceptions
if ((filterContext.Exception as ValidationException) != null)
{
var result = new ContentResult();
//Add errors to Model State so they are handled auto-magically
foreach (var validationsfailures in (filterContext.Exception as ValidationException).Errors)
{
filterContext.Controller.ViewData.ModelState.AddModelError(validationsfailures.PropertyName,validationsfailures.ErrorMessage);
}
//convert to json and return to ajax request
string content = JsonConvert.SerializeObject(filterContext.Controller.ViewData.ModelState,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
result.Content = content;
result.ContentType = "application/json";
filterContext.HttpContext.Response.StatusCode = 400;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.Result = result;
filterContext.ExceptionHandled = true;
}
}
}
and I wire up here
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
..
..
filters.Add(new ValidationExceptionHandlerErrorAttribute());
}
Upvotes: 3