@@ -20,6 +20,7 @@ public async Task SupportsXmlCommentsOnOperationsFromMinimalApis()
2020using Microsoft.Extensions.DependencyInjection;
2121using Microsoft.AspNetCore.Http.HttpResults;
2222using Microsoft.AspNetCore.Http;
23+ using Microsoft.AspNetCore.Mvc;
2324
2425var builder = WebApplication.CreateBuilder();
2526
@@ -44,6 +45,10 @@ public async Task SupportsXmlCommentsOnOperationsFromMinimalApis()
4445app.MapGet("/15", RouteHandlerExtensionMethods.Get15);
4546app.MapPost("/16", RouteHandlerExtensionMethods.Post16);
4647app.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);
4752
4853app.Run();
4954
@@ -207,10 +212,81 @@ public static void Post16(Example example)
207212 public static int[][] Get17(int[] args)
208213 {
209214 return [[1, 2, 3], [4, 5, 6], [7, 8, 9], args];
215+ }
210216
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");
211251 }
212252}
213253
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+
214290public class User
215291{
216292 public string Username { get; set; } = string.Empty;
@@ -232,6 +308,69 @@ public Example(Func<object?, int> function, object? state) : base(function, stat
232308 {
233309 }
234310}
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+ }
235374""" ;
236375 var generator = new XmlCommentGenerator ( ) ;
237376 await SnapshotTestHelper . Verify ( source , generator , out var compilation ) ;
@@ -304,6 +443,51 @@ await SnapshotTestHelper.VerifyOpenApi(compilation, document =>
304443
305444 var path17 = document . Paths [ "/17" ] . Operations [ HttpMethod . Get ] ;
306445 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 ) ;
307491 } ) ;
308492 }
309493}
0 commit comments