Search code examples
c#asp.net-coreasp.net-core-2.0fluentvalidationmodelstate

How can I intercept FluentValidation error response so I can format it to my standard


I am working on an ASP.NET Core 2.1 API that currently has a global ValidateModelAttribute filter that intercepts the context.ModelState in the OnActionExecuting method so it can format any modelstate errors to match the project design standard for error messages.

This is working well. However, I decided to add FluentValidation to the project and even though it is also it is also working correctly, it returns the modelstate response without hitting the OnActionExecuting method in the ValidateModelAttribute filter class.

Here is the code in Startup --> ConfigureServices method for AddMvc

        services.AddMvc(config =>
            {
                config.Filters.Add(typeof(ValidateModelAttribute)); 
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<ServiceTypeCodeValidator>())
            .AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

Here is the ValidateModelAttribute class itself, just for reference;

public class ValidateModelAttribute : ActionFilterAttribute
{
    /// <summary>
    /// Validates model state upon action execution
    /// </summary>
    /// <param name="context">ActionExecutingContext object</param>
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.ModelState.IsValid) return;
        var errorList = context.ModelState.Where(ms => ms.Value.Errors.Any()).ToDictionary(
            kvp => kvp.Key,
            kvp => kvp.Value.Errors.Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception.Message : e.ErrorMessage).ToArray()
        );

        var validationErrors = new ValidationErrors();
        foreach (var item in errorList)
        {
            foreach (var message in item.Value)
            {
                if (validationErrors.Errors.ContainsKey(item.Key))
                {
                    validationErrors.Errors[item.Key].Add(message);
                }
                else
                {
                    validationErrors.Errors.Add(item.Key, new List<string>() { message });
                }
            }
        }

        var globalError = new GlobalError { Errors = errorList };
        context.Result = new BadRequestObjectResult(globalError);
    }

}

I assume that since this is the asp.net pipeline and AddFluentValidation comes after the config.filters.Add line, that this is why I am not able to override the error message from FluentValidation via the ValidateModelAttribute filter.

So my question is, does FluentValidation provide any kind of hook I can override to format the modelstate error response to match the project error message standard?


Solution

  • When you say returns the ModelState response do you mean the default .NET response? If so just add this to startup

    services.Configure<Microsoft.AspNetCore.Mvc.ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });