-
Notifications
You must be signed in to change notification settings - Fork 10.3k
StatusCodePages middleware returns both JSON Problem Details & plaintext content for responses to requests from browsers #45678
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
Comments
This check should have prevented that: aspnetcore/src/Middleware/Diagnostics/src/StatusCodePage/StatusCodePagesOptions.cs Line 37 in 2b63a5f
The response must be buffered? The easy fix is to make that line an |
Ah interesting, I only tried reproducing by launching from VS which would inject the BrowserLink/Refresh middleware so almost certainly buffered. |
Confirmed it doesn't repro when launching from the cmd line with |
Triage: We think it might be related to the change in behavior in the @MackinnonBuck Do you know if the PR to fix this in .NET 7 has been approved? We can also do what Chris mentioned here (#45678 (comment)). cc: @brunolins16 |
Thanks for contacting us. We're moving this issue to the |
@captainsafia The PR has been approved. I just left a comment asking if we're clear to merge it (I'm not sure what the rules are regarding when merging into servicing release branches is allowed). |
@MackinnonBuck link? Wait for the build team to merge servicing PRs. |
Oh, I thought you were referring to a fix for this issue. This issue should still be fixed regardless. |
@Tratcher I wasn't able to reproduce (buffered or not) and a quick look seems move to an else might not be possible since this can skip all aspnetcore/src/Middleware/Diagnostics/src/StatusCodePage/StatusCodePagesOptions.cs Line 29 in 2cd5873
I am planning to change the check to something like this, that might be good enough: aspnetcore/src/Middleware/Diagnostics/src/StatusCodePage/StatusCodePagesMiddleware.cs Lines 67 to 72 in 2cd5873
Thoughts? |
Background and MotivationI have been talking with @Tratcher and we believe that we are trying to work around a wrong decision about the Just for context, a ProblemDetails will not be written when all of the registered As an example, the
Proposed APInamespace Microsoft.AspNetCore.Http;
public interface IProblemDetailsService
{
ValueTask WriteAsync(ProblemDetailsContext context);
+ async ValueTask<bool> TryWriteAsync(ProblemDetailsContext context)
+ {
+ await WriteAsync(context);
+ return true;
+ }
} Usage Examplesvar problemDetailsService = httpContext.RequestServices.GetService<IProblemDetailsService>();
if (problemDetailsService == null ||
!await problemDetailsService.TryWriteAsync(new() { HttpContext = httpContext }))
{
// Your fallback behavior, since problem details was not able to be written.
} Alternative Designspublic interface IProblemDetailsService
{
ValueTask WriteAsync(ProblemDetailsContext context);
+ bool CanWrite(ProblemDetailsContext context);
} Example var problemDetailsService = httpContext.RequestServices.GetService<IProblemDetailsService>();
var context = new ProblemDetailsContext(){ HttpContext = httpContext };
if (problemDetailsService != null && problemDetailsService.CanWrite(context))
{
await problemDetailsService.WriteAsync(context)
} RisksTo be consistent with the Parse/TryParse behavior, as part of this proposal we should change our |
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
Async APIs can't have out parameters. One other alternative: IProblemDetailsService.CanWrite(ProblemDetailsContext ) that mirrors IProblemDetailsWriter |
I proposed it while writing the API suggestion and I completely missed this. Thanks |
API Review Notes:
The TryWrite API looks good! namespace Microsoft.AspNetCore.Http;
public interface IProblemDetailsService
{
ValueTask WriteAsync(ProblemDetailsContext context);
+ async ValueTask<bool> TryWriteAsync(ProblemDetailsContext context)
+ {
+ await WriteAsync(context);
+ return context.HttpContext.Response.HasStarted;
+ }
} |
Is there a way to fix this behavior in .NET 7? |
We don't typically backport bug fixes that include a new API. @DamianEdwards was there a workaround for this other than running the app from the CLI when you ran into it? |
The behavior in the browser refresh middleware injected by Visual Studio was fixed in 7.0.2xx back in November 2022 so I'd ensure you're running the latest version of Visual Studio and confirm you have the 7.0.202 SDK installed. If the behavior is still observed it could be due to another middleware in the pipeline doing "bad things". |
We're definitely not backporting new API, but it should be possible to work around this issue. The issue happens when // StatusCodePages would work here because the original stream was put back
// before it attempts to write and chedk context.Resposne.HasStarted.
//app.UseStatusCodePages();
// Example buffering middleware. Thanks Bing Chat!
app.Use(async (context, next) =>
{
var bodyStream = context.Response.Body;
try
{
using var bufferStream = new MemoryStream();
context.Response.Body = bufferStream;
await next();
bufferStream.Seek(0, SeekOrigin.Begin);
await bufferStream.CopyToAsync(bodyStream);
}
finally
{
context.Response.Body = bodyStream;
}
});
// StatusCodePages breaks here because context.Response.Body is a MemoryStream
// that does not pass through writes to the response until after UseSatatCodePages exits.
app.UseStatusCodePages(); The fix is to call If you just need to log the status code pages, but not delay the response, you can pass through the writes like our HttpLogging ResponseBufferingStream does rather than waiting for middleware to call Worst case scenario, you could override |
Moving Thanks. Both answers were very helpful. |
Is there an existing issue for this?
Describe the bug
The
StatusCodePagesMiddleware
is returning both JSON Problem Details and plain text content (concatenated together) when the request'sAccept
header contains certain combinations of media types. This can be easily seen by making a request from a browser (reproduced using Edge latest on Windows).Expected Behavior
The response should only contain either plain text or JSON Problem Details content, depending on the value of the
Accept
header.Steps To Reproduce
Program.cs
add a call tobuilder.Services.AddProblemDetails()
to enable theIProblemDetailsService
Program.cs
add a call toapp.UseStatusCodePages()
to add theStatusCodePagesMiddleware
to the pipelineExample
Program.cs
:Result:

Accet
header content for request from browser:Exceptions (if any)
No response
.NET Version
7.0.200-preview.22605.5
Anything else?
No response
The text was updated successfully, but these errors were encountered: