@@ -20,6 +20,7 @@ public async Task SupportsXmlCommentsOnOperationsFromMinimalApis()
20
20
using Microsoft.Extensions.DependencyInjection;
21
21
using Microsoft.AspNetCore.Http.HttpResults;
22
22
using Microsoft.AspNetCore.Http;
23
+ using Microsoft.AspNetCore.Mvc;
23
24
24
25
var builder = WebApplication.CreateBuilder();
25
26
@@ -44,6 +45,10 @@ public async Task SupportsXmlCommentsOnOperationsFromMinimalApis()
44
45
app.MapGet("/15", RouteHandlerExtensionMethods.Get15);
45
46
app.MapPost("/16", RouteHandlerExtensionMethods.Post16);
46
47
app.MapGet("/17", RouteHandlerExtensionMethods.Get17);
48
+ app.MapPost("/18", RouteHandlerExtensionMethods.Post18);
49
+ app.MapPost("/19", RouteHandlerExtensionMethods.Post19);
50
+ app.MapGet("/20", RouteHandlerExtensionMethods.Get20);
51
+ app.MapGet("/21", RouteHandlerExtensionMethods.Get21);
47
52
48
53
app.Run();
49
54
@@ -207,10 +212,81 @@ public static void Post16(Example example)
207
212
public static int[][] Get17(int[] args)
208
213
{
209
214
return [[1, 2, 3], [4, 5, 6], [7, 8, 9], args];
215
+ }
210
216
217
+ /// <summary>
218
+ /// A summary of Post18.
219
+ /// </summary>
220
+ public static int Post18([AsParameters] FirstParameters queryParameters, [AsParameters] SecondParameters bodyParameters)
221
+ {
222
+ return 0;
223
+ }
224
+
225
+ /// <summary>
226
+ /// Tests mixed regular and AsParameters with examples.
227
+ /// </summary>
228
+ /// <param name="regularParam">A regular parameter with documentation.</param>
229
+ /// <param name="mixedParams">Mixed parameter class with various types.</param>
230
+ public static IResult Post19(string regularParam, [AsParameters] MixedParametersClass mixedParams)
231
+ {
232
+ return TypedResults.Ok($"Regular: {regularParam}, Email: {mixedParams.Email}");
233
+ }
234
+
235
+ /// <summary>
236
+ /// Tests AsParameters with different binding sources.
237
+ /// </summary>
238
+ /// <param name="bindingParams">Parameters from different sources.</param>
239
+ public static IResult Get20([AsParameters] BindingSourceParametersClass bindingParams)
240
+ {
241
+ return TypedResults.Ok($"Query: {bindingParams.QueryParam}, Header: {bindingParams.HeaderParam}");
242
+ }
243
+
244
+ /// <summary>
245
+ /// Tests XML documentation priority order (value > returns > summary).
246
+ /// </summary>
247
+ /// <param name="priorityParams">Parameters demonstrating XML doc priority.</param>
248
+ public static IResult Get21([AsParameters] XmlDocPriorityParametersClass priorityParams)
249
+ {
250
+ return TypedResults.Ok($"Processed parameters");
211
251
}
212
252
}
213
253
254
+ public class FirstParameters
255
+ {
256
+ /// <summary>
257
+ /// The name of the person.
258
+ /// </summary>
259
+ public string? Name { get; set; }
260
+ /// <summary>
261
+ /// The age of the person.
262
+ /// </summary>
263
+ /// <example>30</example>
264
+ public int? Age { get; set; }
265
+ /// <summary>
266
+ /// The user information.
267
+ /// </summary>
268
+ /// <example>
269
+ /// {
270
+ /// "username": "johndoe",
271
+
272
+ /// }
273
+ /// </example>
274
+ public User? User { get; set; }
275
+ }
276
+
277
+ public class SecondParameters
278
+ {
279
+ /// <summary>
280
+ /// The description of the project.
281
+ /// </summary>
282
+ public string? Description { get; set; }
283
+ /// <summary>
284
+ /// The service used for testing.
285
+ /// </summary>
286
+ [FromServices]
287
+ public Example Service { get; set; }
288
+ }
289
+
214
290
public class User
215
291
{
216
292
public string Username { get; set; } = string.Empty;
@@ -232,6 +308,69 @@ public Example(Func<object?, int> function, object? state) : base(function, stat
232
308
{
233
309
}
234
310
}
311
+
312
+ public class MixedParametersClass
313
+ {
314
+ /// <summary>
315
+ /// The user's email address.
316
+ /// </summary>
317
+ /// <example>"[email protected] "</example>
318
+ public string? Email { get; set; }
319
+
320
+ /// <summary>
321
+ /// The user's age in years.
322
+ /// </summary>
323
+ /// <example>25</example>
324
+ public int Age { get; set; }
325
+
326
+ /// <summary>
327
+ /// Whether the user is active.
328
+ /// </summary>
329
+ /// <example>true</example>
330
+ public bool IsActive { get; set; }
331
+ }
332
+
333
+ public class BindingSourceParametersClass
334
+ {
335
+ /// <summary>
336
+ /// Query parameter from URL.
337
+ /// </summary>
338
+ [FromQuery]
339
+ public string? QueryParam { get; set; }
340
+
341
+ /// <summary>
342
+ /// Header value from request.
343
+ /// </summary>
344
+ [FromHeader]
345
+ public string? HeaderParam { get; set; }
346
+ }
347
+
348
+ public class XmlDocPriorityParametersClass
349
+ {
350
+ /// <summary>
351
+ /// Property with only summary documentation.
352
+ /// </summary>
353
+ public string? SummaryOnlyProperty { get; set; }
354
+
355
+ /// <summary>
356
+ /// Property with summary documentation that should be overridden.
357
+ /// </summary>
358
+ /// <returns>Returns-based description that should take precedence over summary.</returns>
359
+ public string? SummaryAndReturnsProperty { get; set; }
360
+
361
+ /// <summary>
362
+ /// Property with all three types of documentation.
363
+ /// </summary>
364
+ /// <returns>Returns-based description that should be overridden by value.</returns>
365
+ /// <value>Value-based description that should take highest precedence.</value>
366
+ public string? AllThreeProperty { get; set; }
367
+
368
+ /// <returns>Returns-only description.</returns>
369
+ public string? ReturnsOnlyProperty { get; set; }
370
+
371
+ /// <value>Value-only description.</value>
372
+ public string? ValueOnlyProperty { get; set; }
373
+ }
235
374
""" ;
236
375
var generator = new XmlCommentGenerator ( ) ;
237
376
await SnapshotTestHelper . Verify ( source , generator , out var compilation ) ;
@@ -304,6 +443,51 @@ await SnapshotTestHelper.VerifyOpenApi(compilation, document =>
304
443
305
444
var path17 = document . Paths [ "/17" ] . Operations [ HttpMethod . Get ] ;
306
445
Assert . Equal ( "A summary of Get17." , path17 . Summary ) ;
446
+
447
+ var path18 = document . Paths [ "/18" ] . Operations [ HttpMethod . Post ] ;
448
+ Assert . Equal ( "A summary of Post18." , path18 . Summary ) ;
449
+ Assert . Equal ( "The name of the person." , path18 . Parameters [ 0 ] . Description ) ;
450
+ Assert . Equal ( "The age of the person." , path18 . Parameters [ 1 ] . Description ) ;
451
+ Assert . Equal ( 30 , path18 . Parameters [ 1 ] . Example . GetValue < int > ( ) ) ;
452
+ Assert . Equal ( "The description of the project." , path18 . Parameters [ 2 ] . Description ) ;
453
+ Assert . Equal ( "The user information." , path18 . RequestBody . Description ) ;
454
+ var path18RequestBody = path18 . RequestBody . Content [ "application/json" ] ;
455
+ var path18Example = Assert . IsAssignableFrom < JsonNode > ( path18RequestBody . Example ) ;
456
+ Assert . Equal ( "johndoe" , path18Example [ "username" ] . GetValue < string > ( ) ) ;
457
+ Assert . Equal ( "[email protected] " , path18Example [ "email" ] . GetValue < string > ( ) ) ;
458
+
459
+ var path19 = document . Paths [ "/19" ] . Operations [ HttpMethod . Post ] ;
460
+ Assert . Equal ( "Tests mixed regular and AsParameters with examples." , path19 . Summary ) ;
461
+ Assert . Equal ( "A regular parameter with documentation." , path19 . Parameters [ 0 ] . Description ) ;
462
+ Assert . Equal ( "The user's email address." , path19 . Parameters [ 1 ] . Description ) ;
463
+ Assert . Equal ( "[email protected] " , path19 . Parameters [ 1 ] . Example . GetValue < string > ( ) ) ;
464
+ Assert . Equal ( "The user's age in years." , path19 . Parameters [ 2 ] . Description ) ;
465
+ Assert . Equal ( 25 , path19 . Parameters [ 2 ] . Example . GetValue < int > ( ) ) ;
466
+ Assert . Equal ( "Whether the user is active." , path19 . Parameters [ 3 ] . Description ) ;
467
+ Assert . True ( path19 . Parameters [ 3 ] . Example . GetValue < bool > ( ) ) ;
468
+
469
+ var path20 = document . Paths [ "/20" ] . Operations [ HttpMethod . Get ] ;
470
+ Assert . Equal ( "Tests AsParameters with different binding sources." , path20 . Summary ) ;
471
+ Assert . Equal ( "Query parameter from URL." , path20 . Parameters [ 0 ] . Description ) ;
472
+ Assert . Equal ( "Header value from request." , path20 . Parameters [ 1 ] . Description ) ;
473
+
474
+ // Test XML documentation priority order: value > returns > summary
475
+ var path22 = document . Paths [ "/21" ] . Operations [ HttpMethod . Get ] ;
476
+ // Find parameters by name for clearer assertions
477
+ var summaryOnlyParam = path22 . Parameters . First ( p => p . Name == "SummaryOnlyProperty" ) ;
478
+ Assert . Equal ( "Property with only summary documentation." , summaryOnlyParam . Description ) ;
479
+
480
+ var summaryAndReturnsParam = path22 . Parameters . First ( p => p . Name == "SummaryAndReturnsProperty" ) ;
481
+ Assert . Equal ( "Returns-based description that should take precedence over summary." , summaryAndReturnsParam . Description ) ;
482
+
483
+ var allThreeParam = path22 . Parameters . First ( p => p . Name == "AllThreeProperty" ) ;
484
+ Assert . Equal ( "Value-based description that should take highest precedence." , allThreeParam . Description ) ;
485
+
486
+ var returnsOnlyParam = path22 . Parameters . First ( p => p . Name == "ReturnsOnlyProperty" ) ;
487
+ Assert . Equal ( "Returns-only description." , returnsOnlyParam . Description ) ;
488
+
489
+ var valueOnlyParam = path22 . Parameters . First ( p => p . Name == "ValueOnlyProperty" ) ;
490
+ Assert . Equal ( "Value-only description." , valueOnlyParam . Description ) ;
307
491
} ) ;
308
492
}
309
493
}
0 commit comments