FluentValidation.AutoValidation icon indicating copy to clipboard operation
FluentValidation.AutoValidation copied to clipboard

Enhance IFluentValidationAutoValidationResultFactory and support async operations

Open baranacikgoz opened this issue 9 months ago • 1 comments

The current implementation of the IFluentValidationAutoValidationResultFactory relies on returning a IResult object directly.

However, this approach is limiting and won't allow us to use built-in IProblemDetailsService. As an example, I have an IProblemDetailsService setup in my project, and whenever I'll return a problem details, I rely on it, it adds the instance, traceId, environment, node and etc. automatically for me;

image

The current implementation of IFluentValidationAutoValidationResultFactory is forcing us to return an IResult object. Which means, one must duplicate the problem details setup once in services.AddProblemDetails and again in IFluentValidationAutoValidationResultFactory.

My proposal is to change the method signature from

IResult CreateResult(EndpointFilterInvocationContext context, ValidationResult validationResult);

To

ValueTask WriteResult(EndpointFilterInvocationContext context, ValidationResult validationResult);

Hence, allow us to use IProblemDetailsService.WriteAsync like this;

internal sealed class CustomFluentValidationResultFactory(
    IStringLocalizer<ResxLocalizer> localizer,
    IProblemDetailsService problemDetailsService
    ) : IFluentValidationAutoValidationResultFactory
{

    public async ValueTask WriteResult(EndpointFilterInvocationContext context, ValidationResult validationResult)
    {
        var problemDetails = new ProblemDetails
        {
            Status = (int)HttpStatusCode.BadRequest,
            Title = localizer[nameof(HttpStatusCode.BadRequest)],
        };

        problemDetails.AddErrorKey(nameof(ValidationFailure));
        problemDetails.AddErrors(validationResult.Errors.Select(x => x.ErrorMessage));

        context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
        await problemDetailsService.WriteAsync(new ProblemDetailsContext
        {
            HttpContext = context.HttpContext,
            ProblemDetails = problemDetails,
        });
    }
}

I'd love to help this refactor. What are your thoughts?

baranacikgoz avatar Jan 15 '25 21:01 baranacikgoz