Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Setting ProblemDetailsContext.ProblemDetails
to an instance of HttpValidationProblemDetails
and subsequently passing that context instance to ProblemDetailsService.WriteAsync
does not write out the error details contained on HttpValidationProblemDetails.Errors
.
This is possibly caused by the fact that DefaultProblemDetailsWriter
uses an internal JsonSerializerContext
if no extensions are added to the problem details instance, and that JSON context is only decorated to support the ProblemDetails
type.
Expected Behavior
Using ProblemDetailsService
to write out an HttpValidationProblemDetails
should include the errors in the resultant JSON content.
Steps To Reproduce
Create an endpoint filter that will use the IProblemDetailsService
to write out the JSON content if an endpoint returns ProblemHttpResult
or ProblemDetails
directly:
public class ProblemDetailsServiceEndpointFilter : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
=> await next(context) switch
{
ProblemHttpResult problemHttpResult => new ProblemDetailsServiceAwareResult(problemHttpResult.StatusCode, problemHttpResult.ProblemDetails),
ProblemDetails problemDetails => new ProblemDetailsServiceAwareResult(null, problemDetails),
{ } result => result,
null => null
};
private class ProblemDetailsServiceAwareResult : IResult, IValueHttpResult, IValueHttpResult<ProblemDetails>
{
private readonly int? _statusCode;
public ProblemDetailsServiceAwareResult(int? statusCode, ProblemDetails problemDetails)
{
_statusCode = statusCode ?? problemDetails.Status;
Value = problemDetails;
}
public ProblemDetails Value { get; }
object? IValueHttpResult.Value => Value;
public async Task ExecuteAsync(HttpContext httpContext)
{
if (httpContext.RequestServices.GetService<IProblemDetailsService>() is IProblemDetailsService problemDetailsService)
{
if (_statusCode is { } statusCode)
{
httpContext.Response.StatusCode = statusCode;
}
await problemDetailsService.WriteAsync(new()
{
HttpContext = httpContext,
ProblemDetails = Value
});
}
}
}
}
Add two endpoints that return Results.ValidationProblem
, one with the filter and one without:
app.MapGet("/test", () =>
{
var dict = new Dictionary<string, string[]>();
dict.Add("Value1", new[] { "Problem 1", "Problem 2" });
return Results.ValidationProblem(dict);
});
var general = app.MapGroup("").AddEndpointFilter(new ProblemDetailsServiceEndpointFilter());
general.MapGet("/testfiltered", () =>
{
var dict = new Dictionary<string, string[]>();
dict.Add("Value1", new[] { "Problem 1", "Problem 2" });
return Results.ValidationProblem(dict);
});
Make requests to both endpoints and observe that the filtered endpoint doesn't include the error details.
Exceptions (if any)
No response
.NET Version
7.0.200-preview.22605.5
Anything else?
No response