1414
1515namespace Microsoft . AspNetCore . Http . Extensions . Tests ;
1616
17- public class ValidationEndpointFilterFactoryTests
17+ public class ValidationEndpointFilterFactoryTests : LoggedTest
1818{
1919 [ Fact ]
2020 public async Task GetHttpValidationProblemDetailsWhenProblemDetailsServiceNotRegistered ( )
@@ -26,7 +26,7 @@ public async Task GetHttpValidationProblemDetailsWhenProblemDetailsServiceNotReg
2626 var builder = new DefaultEndpointRouteBuilder ( new ApplicationBuilder ( serviceProvider ) ) ;
2727
2828 // Act - Create one endpoint with validation
29- builder . MapGet ( "test-enabled " , ( [ Range ( 5 , 10 ) ] int param ) => "Validation enabled here." ) ;
29+ builder . MapGet ( "validation-test " , ( [ Range ( 5 , 10 ) ] int param ) => "Validation enabled here." ) ;
3030
3131 // Build the endpoints
3232 var dataSource = Assert . Single ( builder . DataSources ) ;
@@ -73,7 +73,7 @@ public async Task UseProblemDetailsServiceWhenAddedInServiceCollection()
7373 var builder = new DefaultEndpointRouteBuilder ( new ApplicationBuilder ( serviceProvider ) ) ;
7474
7575 // Act - Create one endpoint with validation
76- builder . MapGet ( "test-enabled " , ( [ Range ( 5 , 10 ) ] int param ) => "Validation enabled here." ) ;
76+ builder . MapGet ( "validation-test " , ( [ Range ( 5 , 10 ) ] int param ) => "Validation enabled here." ) ;
7777
7878 // Build the endpoints
7979 var dataSource = Assert . Single ( builder . DataSources ) ;
@@ -101,6 +101,7 @@ public async Task UseProblemDetailsServiceWhenAddedInServiceCollection()
101101 ms . Seek ( 0 , SeekOrigin . Begin ) ;
102102 var problemDetails = await JsonSerializer . DeserializeAsync < ProblemDetails > ( ms , JsonSerializerOptions . Web ) ;
103103
104+ // Check if the response is an actual ProblemDetails object
104105 Assert . Equal ( "https://tools.ietf.org/html/rfc9110#section-15.5.1" , problemDetails . Type ) ;
105106 Assert . Equal ( "One or more validation errors occurred." , problemDetails . Title ) ;
106107 Assert . Equal ( StatusCodes . Status400BadRequest , problemDetails . Status ) ;
@@ -111,6 +112,67 @@ public async Task UseProblemDetailsServiceWhenAddedInServiceCollection()
111112 Assert . True ( errors . EnumerateObject ( ) . Count ( ) == 1 ) ;
112113 }
113114
115+ [ Fact ]
116+ public async Task UseProblemDetailsServiceWithCallbackWhenAddedInServiceCollection ( )
117+ {
118+ var services = new ServiceCollection ( ) ;
119+ services . AddValidation ( ) ;
120+
121+ services . AddProblemDetails ( options =>
122+ {
123+ options . CustomizeProblemDetails = context =>
124+ {
125+ context . ProblemDetails . Extensions . Add ( "timestamp" , DateTimeOffset . Now ) ;
126+ } ;
127+ } ) ;
128+
129+ var serviceProvider = services . BuildServiceProvider ( ) ;
130+
131+ var builder = new DefaultEndpointRouteBuilder ( new ApplicationBuilder ( serviceProvider ) ) ;
132+
133+ // Act - Create one endpoint with validation
134+ builder . MapGet ( "validation-test" , ( [ Range ( 5 , 10 ) ] int param ) => "Validation enabled here." ) ;
135+
136+ // Build the endpoints
137+ var dataSource = Assert . Single ( builder . DataSources ) ;
138+ var endpoints = dataSource . Endpoints ;
139+
140+ // Get filter factories from endpoint
141+ var endpoint = endpoints [ 0 ] ;
142+
143+ var context = new DefaultHttpContext
144+ {
145+ RequestServices = serviceProvider
146+ } ;
147+
148+ context . Request . Method = "GET" ;
149+ context . Request . QueryString = new QueryString ( "?param=15" ) ;
150+ using var ms = new MemoryStream ( ) ;
151+ context . Response . Body = ms ;
152+
153+ await endpoint . RequestDelegate ( context ) ;
154+
155+ // Assert
156+ Assert . Equal ( StatusCodes . Status400BadRequest , context . Response . StatusCode ) ;
157+ Assert . StartsWith ( MediaTypeNames . Application . ProblemJson , context . Response . ContentType , StringComparison . OrdinalIgnoreCase ) ;
158+
159+ ms . Seek ( 0 , SeekOrigin . Begin ) ;
160+ var problemDetails = await JsonSerializer . DeserializeAsync < ProblemDetails > ( ms , JsonSerializerOptions . Web ) ;
161+
162+ // Check if the response is an actual ProblemDetails object
163+ Assert . Equal ( "https://tools.ietf.org/html/rfc9110#section-15.5.1" , problemDetails . Type ) ;
164+ Assert . Equal ( "One or more validation errors occurred." , problemDetails . Title ) ;
165+ Assert . Equal ( StatusCodes . Status400BadRequest , problemDetails . Status ) ;
166+
167+ // Check that ProblemDetails contains the errors object with 1 validation error
168+ Assert . True ( problemDetails . Extensions . TryGetValue ( "errors" , out var errorsObj ) ) ;
169+ var errors = Assert . IsType < JsonElement > ( errorsObj ) ;
170+ Assert . True ( errors . EnumerateObject ( ) . Count ( ) == 1 ) ;
171+
172+ // Check that ProblemDetails customizations are applied in the response
173+ Assert . True ( problemDetails . Extensions . ContainsKey ( "timestamp" ) ) ;
174+ }
175+
114176 private class DefaultEndpointRouteBuilder ( IApplicationBuilder applicationBuilder ) : IEndpointRouteBuilder
115177 {
116178 private IApplicationBuilder ApplicationBuilder { get ; } = applicationBuilder ?? throw new ArgumentNullException ( nameof ( applicationBuilder ) ) ;
0 commit comments