Skip to content

Respect ProblemDetailsService in default model validation filter #61219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
captainsafia opened this issue Mar 28, 2025 · 1 comment
Open

Respect ProblemDetailsService in default model validation filter #61219

captainsafia opened this issue Mar 28, 2025 · 1 comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-validation Issues related to model validation in minimal and controller-based APIs
Milestone

Comments

@captainsafia
Copy link
Member

Gathered from #46349 (comment) and #46349 (comment).

We need to figure out a way to get the ValidationEndpointFilterFactory implementation to plug-in to the ProblemDetailsService so that it can respect global ProblemDetails-related configuration provided by the user.

This is usually supported via TypedResults but since there are circular dependencies issues we might just need to interact with the ProblemDetails service directly.

@captainsafia captainsafia added area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-validation Issues related to model validation in minimal and controller-based APIs labels Mar 28, 2025
@captainsafia captainsafia added this to the Backlog milestone Mar 28, 2025
@captainsafia captainsafia marked this as a duplicate of #61533 Apr 28, 2025
@marcominerva
Copy link
Contributor

marcominerva commented Apr 29, 2025

@captainsafia, I would like to help with this task, so I'm digging into the ValidationEndpointFilterFactory implementation:

if (validatableContext.ValidationErrors is { Count: > 0 })
{
context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
context.HttpContext.Response.ContentType = "application/problem+json";
return await ValueTask.FromResult(new HttpValidationProblemDetails(validatableContext.ValidationErrors));
}

In this code block, getting the IProblemDetailsService from DI should be straightforward. But since the method needs to return a value, I ended up writing something like this:

if (validatableContext.ValidationErrors is { Count: > 0 })
{
    context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;

    var problemDetails = new HttpValidationProblemDetails(validatableContext.ValidationErrors);
    var problemDetailsService = context.HttpContext.RequestServices.GetService<IProblemDetailsService>();

    if (problemDetailsService is not null)
    {
        if (await problemDetailsService.TryWriteAsync(new()
        {
            HttpContext = context.HttpContext,
            ProblemDetails = problemDetails
        }))
        {
            // We need to prevent further execution.
            return await ValueTask.FromResult(EmptyHttpResult.Instance);
        }
    }

    // Fallback to the default implementation
    context.HttpContext.Response.ContentType = MediaTypeNames.Application.ProblemJson;
    return await ValueTask.FromResult(problemDetails);
}

Before creating a PR, I’d like to know if you think this is the right solution. Do you have any suggestions for improving it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-validation Issues related to model validation in minimal and controller-based APIs
Projects
None yet
Development

No branches or pull requests

2 participants