From 15242c5025cab8e947a986683f91f5237cb3d83b Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Sat, 9 Dec 2023 20:39:33 +0330 Subject: [PATCH 1/4] Set IExceptionHandlerFeature on DeveloperExceptionPageMiddleware --- .../DeveloperExceptionPageMiddlewareImpl.cs | 11 +++++ .../ExceptionHandlerMiddlewareTest.cs | 41 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs index 47320c6ecdd3..d5b647ccef0c 100644 --- a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs +++ b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs @@ -148,6 +148,17 @@ public async Task Invoke(HttpContext context) context.Response.StatusCode = 500; } + var exceptionHandlerFeature = new ExceptionHandlerFeature() + { + Error = ex, + Path = context.Request.Path, + Endpoint = context.GetEndpoint(), + RouteValues = context.Features.Get()?.RouteValues + }; + + context.Features.Set(exceptionHandlerFeature); + context.Features.Set(exceptionHandlerFeature); + await _exceptionHandler(new ErrorContext(context, ex)); const string eventName = "Microsoft.AspNetCore.Diagnostics.UnhandledException"; diff --git a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs index 31c3fa12f5df..48fca3b67d9d 100644 --- a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs +++ b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs @@ -315,6 +315,47 @@ public async Task Metrics_ExceptionThrown_Unhandled_Reported() m => AssertRequestException(m, "System.InvalidOperationException", "unhandled")); } + [Fact] + public async Task ExceptionFeatureSetOnDeveloperExceptionPage() + { + // Arrange + using var host = new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseTestServer() + .Configure(app => + { + app.Use(async (context, next) => + { + await next(); + + var exceptionHandlerFeature = context.Features.GetRequiredFeature(); + + Assert.NotNull(exceptionHandlerFeature); + Assert.Equal("Test exception", exceptionHandlerFeature.Error.Message); + Assert.Equal(context.Request.Path, exceptionHandlerFeature.Path); + }); + app.UseExceptionHandler(exceptionApp => + { + exceptionApp.Run(context => Task.CompletedTask); + }); + app.Run(context => + { + throw new Exception("Test exception"); + }); + + }); + }).Build(); + + await host.StartAsync(); + + var server = host.GetTestServer(); + var request = new HttpRequestMessage(HttpMethod.Get, "/path"); + + var response = await server.CreateClient().SendAsync(request); + } + private static void AssertRequestException(CollectedMeasurement measurement, string exceptionName, string result, string handler = null) { Assert.Equal(1, measurement.Value); From 1a3fda55135cfdb0f81da8c51e3272902103ea4b Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Tue, 12 Dec 2023 11:24:42 +0330 Subject: [PATCH 2/4] Refactor --- .../DeveloperExceptionPageMiddlewareImpl.cs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs index d5b647ccef0c..844b53d9b47c 100644 --- a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs +++ b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs @@ -148,16 +148,7 @@ public async Task Invoke(HttpContext context) context.Response.StatusCode = 500; } - var exceptionHandlerFeature = new ExceptionHandlerFeature() - { - Error = ex, - Path = context.Request.Path, - Endpoint = context.GetEndpoint(), - RouteValues = context.Features.Get()?.RouteValues - }; - - context.Features.Set(exceptionHandlerFeature); - context.Features.Set(exceptionHandlerFeature); + SetExceptionHandlerFeatures(context, ex); await _exceptionHandler(new ErrorContext(context, ex)); @@ -184,6 +175,20 @@ public async Task Invoke(HttpContext context) Justification = "The values being passed into Write have the commonly used properties being preserved with DynamicDependency.")] static void WriteDiagnosticEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(DiagnosticSource diagnosticSource, string name, TValue value) => diagnosticSource.Write(name, value); + + static void SetExceptionHandlerFeatures(HttpContext context, Exception ex) + { + var exceptionHandlerFeature = new ExceptionHandlerFeature() + { + Error = ex, + Path = context.Request.Path, + Endpoint = context.GetEndpoint(), + RouteValues = context.Features.Get()?.RouteValues + }; + + context.Features.Set(exceptionHandlerFeature); + context.Features.Set(exceptionHandlerFeature); + } } // Assumes the response headers have not been sent. If they have, still attempt to write to the body. From c0f8d79d1faa770bc334114d08a89de29939c052 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Tue, 12 Dec 2023 22:01:23 +0330 Subject: [PATCH 3/4] Refactor --- .../DeveloperExceptionPageMiddlewareImpl.cs | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs index 844b53d9b47c..79602d59b034 100644 --- a/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs +++ b/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddlewareImpl.cs @@ -148,9 +148,10 @@ public async Task Invoke(HttpContext context) context.Response.StatusCode = 500; } - SetExceptionHandlerFeatures(context, ex); + var errorContext = new ErrorContext(context, ex); - await _exceptionHandler(new ErrorContext(context, ex)); + SetExceptionHandlerFeatures(errorContext); + await _exceptionHandler(errorContext); const string eventName = "Microsoft.AspNetCore.Diagnostics.UnhandledException"; if (_diagnosticSource.IsEnabled(eventName)) @@ -175,20 +176,6 @@ public async Task Invoke(HttpContext context) Justification = "The values being passed into Write have the commonly used properties being preserved with DynamicDependency.")] static void WriteDiagnosticEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(DiagnosticSource diagnosticSource, string name, TValue value) => diagnosticSource.Write(name, value); - - static void SetExceptionHandlerFeatures(HttpContext context, Exception ex) - { - var exceptionHandlerFeature = new ExceptionHandlerFeature() - { - Error = ex, - Path = context.Request.Path, - Endpoint = context.GetEndpoint(), - RouteValues = context.Features.Get()?.RouteValues - }; - - context.Features.Set(exceptionHandlerFeature); - context.Features.Set(exceptionHandlerFeature); - } } // Assumes the response headers have not been sent. If they have, still attempt to write to the body. @@ -216,17 +203,12 @@ private async Task DisplayExceptionContent(ErrorContext errorContext) { var httpContext = errorContext.HttpContext; - if (_problemDetailsService is not null) - { - SetExceptionHandlerFeatures(errorContext); - } - if (_problemDetailsService == null || !await _problemDetailsService.TryWriteAsync(new() - { - HttpContext = httpContext, - ProblemDetails = CreateProblemDetails(errorContext, httpContext), - Exception = errorContext.Exception - })) + { + HttpContext = httpContext, + ProblemDetails = CreateProblemDetails(errorContext, httpContext), + Exception = errorContext.Exception + })) { httpContext.Response.ContentType = "text/plain; charset=utf-8"; From 500c92fd36e3549669fe328f7b302a9c4602256d Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Mon, 8 Jul 2024 15:40:44 +0330 Subject: [PATCH 4/4] Fix tests --- .../test/UnitTests/ExceptionHandlerMiddlewareTest.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs index 48fca3b67d9d..7b2f3760c197 100644 --- a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs +++ b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs @@ -319,6 +319,8 @@ public async Task Metrics_ExceptionThrown_Unhandled_Reported() public async Task ExceptionFeatureSetOnDeveloperExceptionPage() { // Arrange + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using var host = new HostBuilder() .ConfigureWebHost(webHostBuilder => { @@ -331,10 +333,7 @@ public async Task ExceptionFeatureSetOnDeveloperExceptionPage() await next(); var exceptionHandlerFeature = context.Features.GetRequiredFeature(); - - Assert.NotNull(exceptionHandlerFeature); - Assert.Equal("Test exception", exceptionHandlerFeature.Error.Message); - Assert.Equal(context.Request.Path, exceptionHandlerFeature.Path); + tcs.SetResult(exceptionHandlerFeature); }); app.UseExceptionHandler(exceptionApp => { @@ -354,6 +353,11 @@ public async Task ExceptionFeatureSetOnDeveloperExceptionPage() var request = new HttpRequestMessage(HttpMethod.Get, "/path"); var response = await server.CreateClient().SendAsync(request); + + var feature = await tcs.Task; + Assert.NotNull(feature); + Assert.Equal("Test exception", feature.Error.Message); + Assert.Equal("/path", feature.Path); } private static void AssertRequestException(CollectedMeasurement measurement, string exceptionName, string result, string handler = null)