22// The .NET Foundation licenses this file to you under the MIT license.
33
44using System . Diagnostics ;
5+ using System . Net . Http ;
56using System . Net . Http . Headers ;
7+ using System . Net . Http . Json ;
8+ using System . Text . Json ;
69using Microsoft . AspNetCore . Builder ;
710using Microsoft . AspNetCore . Hosting ;
811using Microsoft . AspNetCore . Http ;
12+ using Microsoft . AspNetCore . Mvc ;
913using Microsoft . AspNetCore . TestHost ;
1014using Microsoft . Extensions . DependencyInjection ;
1115using Microsoft . Extensions . Hosting ;
@@ -14,6 +18,124 @@ namespace Microsoft.AspNetCore.Diagnostics;
1418
1519public class DeveloperExceptionPageMiddlewareTest
1620{
21+ [ Fact ]
22+ public async Task ExceptionHandlerFeatureIsAvailableInCustomizeProblemDetailsWhenUsingExceptionPage ( )
23+ {
24+ // Arrange
25+ using var host = new HostBuilder ( )
26+ . ConfigureServices ( services =>
27+ {
28+ services . AddRouting ( ) ;
29+ services . AddProblemDetails ( configure =>
30+ {
31+ configure . CustomizeProblemDetails = ( context ) =>
32+ {
33+ var feature = context . HttpContext . Features . Get < IExceptionHandlerFeature > ( ) ;
34+ context . ProblemDetails . Extensions . Add ( "OriginalExceptionMessage" , feature ? . Error . Message ) ;
35+ context . ProblemDetails . Extensions . Add ( "EndpointDisplayName" , feature ? . Endpoint ? . DisplayName ) ;
36+ context . ProblemDetails . Extensions . Add ( "RouteValue" , feature ? . RouteValues ? [ "id" ] ) ;
37+ context . ProblemDetails . Extensions . Add ( "Path" , feature ? . Path ) ;
38+ } ;
39+ } ) ;
40+ } )
41+ . ConfigureWebHost ( webHostBuilder =>
42+ {
43+ webHostBuilder
44+ . UseTestServer ( )
45+ . Configure ( app =>
46+ {
47+ app . UseDeveloperExceptionPage ( ) ;
48+ app . UseRouting ( ) ;
49+ app . UseEndpoints ( endpoint =>
50+ {
51+ endpoint . MapGet ( "/test/{id}" , ( int id ) =>
52+ {
53+ throw new Exception ( "Test exception" ) ;
54+ } ) ;
55+ } ) ;
56+ } ) ;
57+ } ) . Build ( ) ;
58+
59+ await host . StartAsync ( ) ;
60+
61+ var server = host . GetTestServer ( ) ;
62+ var request = new HttpRequestMessage ( HttpMethod . Get , "http://localhost/test/1" ) ;
63+ request . Headers . Accept . Add ( new MediaTypeWithQualityHeaderValue ( "application/json" ) ) ;
64+
65+ // Act
66+ var response = await server . CreateClient ( ) . SendAsync ( request ) ;
67+
68+ // Assert
69+ var body = await response . Content . ReadFromJsonAsync < ProblemDetails > ( ) ;
70+ var originalExceptionMessage = ( ( JsonElement ) body . Extensions [ "OriginalExceptionMessage" ] ) . GetString ( ) ;
71+ var endpointDisplayName = ( ( JsonElement ) body . Extensions [ "EndpointDisplayName" ] ) . GetString ( ) ;
72+ var routeValue = ( ( JsonElement ) body . Extensions [ "RouteValue" ] ) . GetString ( ) ;
73+ var path = ( ( JsonElement ) body . Extensions [ "Path" ] ) . GetString ( ) ;
74+ Assert . Equal ( "Test exception" , originalExceptionMessage ) ;
75+ Assert . Contains ( "/test/{id}" , endpointDisplayName ) ;
76+ Assert . Equal ( "1" , routeValue ) ;
77+ Assert . Equal ( "/test/1" , path ) ;
78+ }
79+
80+ [ Fact ]
81+ public async Task ExceptionHandlerPathFeatureIsAvailableInCustomizeProblemDetailsWhenUsingExceptionPage ( )
82+ {
83+ // Arrange
84+ using var host = new HostBuilder ( )
85+ . ConfigureServices ( services =>
86+ {
87+ services . AddRouting ( ) ;
88+ services . AddProblemDetails ( configure =>
89+ {
90+ configure . CustomizeProblemDetails = ( context ) =>
91+ {
92+ var feature = context . HttpContext . Features . Get < IExceptionHandlerPathFeature > ( ) ;
93+ context . ProblemDetails . Extensions . Add ( "OriginalExceptionMessage" , feature ? . Error . Message ) ;
94+ context . ProblemDetails . Extensions . Add ( "EndpointDisplayName" , feature ? . Endpoint ? . DisplayName ) ;
95+ context . ProblemDetails . Extensions . Add ( "RouteValue" , feature ? . RouteValues ? [ "id" ] ) ;
96+ context . ProblemDetails . Extensions . Add ( "Path" , feature ? . Path ) ;
97+ } ;
98+ } ) ;
99+ } )
100+ . ConfigureWebHost ( webHostBuilder =>
101+ {
102+ webHostBuilder
103+ . UseTestServer ( )
104+ . Configure ( app =>
105+ {
106+ app . UseDeveloperExceptionPage ( ) ;
107+ app . UseRouting ( ) ;
108+ app . UseEndpoints ( endpoint =>
109+ {
110+ endpoint . MapGet ( "/test/{id}" , ( int id ) =>
111+ {
112+ throw new Exception ( "Test exception" ) ;
113+ } ) ;
114+ } ) ;
115+ } ) ;
116+ } ) . Build ( ) ;
117+
118+ await host . StartAsync ( ) ;
119+
120+ var server = host . GetTestServer ( ) ;
121+ var request = new HttpRequestMessage ( HttpMethod . Get , "http://localhost/test/1" ) ;
122+ request . Headers . Accept . Add ( new MediaTypeWithQualityHeaderValue ( "application/json" ) ) ;
123+
124+ // Act
125+ var response = await server . CreateClient ( ) . SendAsync ( request ) ;
126+
127+ // Assert
128+ var body = await response . Content . ReadFromJsonAsync < ProblemDetails > ( ) ;
129+ var originalExceptionMessage = ( ( JsonElement ) body . Extensions [ "OriginalExceptionMessage" ] ) . GetString ( ) ;
130+ var endpointDisplayName = ( ( JsonElement ) body . Extensions [ "EndpointDisplayName" ] ) . GetString ( ) ;
131+ var routeValue = ( ( JsonElement ) body . Extensions [ "RouteValue" ] ) . GetString ( ) ;
132+ var path = ( ( JsonElement ) body . Extensions [ "Path" ] ) . GetString ( ) ;
133+ Assert . Equal ( "Test exception" , originalExceptionMessage ) ;
134+ Assert . Contains ( "/test/{id}" , endpointDisplayName ) ;
135+ Assert . Equal ( "1" , routeValue ) ;
136+ Assert . Equal ( "/test/1" , path ) ;
137+ }
138+
17139 [ Fact ]
18140 public async Task UnhandledErrorsWriteToDiagnosticWhenUsingExceptionPage ( )
19141 {
0 commit comments