Skip to content

Commit 7801075

Browse files
committed
refactor: improve exception middleware safety and RFC 7807 compliance
- Add HasStarted check before modifying response - Prevent errors when exception occurs after headers sent - Log warning when unable to write error response - Use authoritative Mozilla documentation for error types
1 parent 7e10631 commit 7801075

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

src/Dotnet.Samples.AspNetCore.WebApi/Extensions/MiddlewareExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ public static class MiddlewareExtensions
1111
/// Adds global exception handling middleware to the application pipeline.
1212
/// This middleware catches unhandled exceptions and returns RFC 7807 compliant error responses.
1313
/// </summary>
14-
/// <param name="app">The web application builder.</param>
15-
/// <returns>The web application builder for method chaining.</returns>
14+
/// <param name="app">The web application used to configure the HTTP pipeline, and routes.</param>
15+
/// <returns>The WebApplication object for method chaining.</returns>
1616
public static WebApplication UseExceptionHandling(this WebApplication app)
1717
{
1818
app.UseMiddleware<ExceptionMiddleware>();

src/Dotnet.Samples.AspNetCore.WebApi/Middlewares/ExceptionMiddleware.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
3535
/// </summary>
3636
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
3737
{
38-
var (statusCode, title) = MapExceptionToStatusCode(exception);
38+
var (status, title) = MapExceptionToStatusCode(exception);
3939

4040
var problemDetails = new ProblemDetails
4141
{
42-
Type = $"https://httpstatuses.com/{statusCode}",
42+
Type = $"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{status}",
4343
Title = title,
44-
Status = statusCode,
44+
Status = status,
4545
Detail = GetExceptionDetail(exception),
4646
Instance = context.Request.Path
4747
};
@@ -55,13 +55,26 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception
5555
"Unhandled exception occurred. TraceId: {TraceId}, Path: {Path}, StatusCode: {StatusCode}",
5656
context.TraceIdentifier,
5757
context.Request.Path,
58-
statusCode
58+
status
5959
);
6060

61-
context.Response.StatusCode = statusCode;
62-
context.Response.ContentType = ProblemDetailsContentType;
61+
// Only modify response if headers haven't been sent yet
62+
if (!context.Response.HasStarted)
63+
{
64+
context.Response.StatusCode = status;
65+
context.Response.ContentType = ProblemDetailsContentType;
6366

64-
await context.Response.WriteAsync(JsonSerializer.Serialize(problemDetails, JsonOptions));
67+
await context.Response.WriteAsync(
68+
JsonSerializer.Serialize(problemDetails, JsonOptions)
69+
);
70+
}
71+
else
72+
{
73+
logger.LogWarning(
74+
"Unable to write error response for TraceId: {TraceId}. Response has already started.",
75+
context.TraceIdentifier
76+
);
77+
}
6578
}
6679

6780
/// <summary>

0 commit comments

Comments
 (0)