diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs
index dcd4f96267..48d07a0684 100644
--- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs
+++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs
@@ -1,4 +1,5 @@
-using System.Reflection;
+using System.Linq;
+using System.Reflection;
using System.Xml.XPath;
using Microsoft.OpenApi.Models;
@@ -15,22 +16,26 @@ public XmlCommentsRequestBodyFilter(XPathDocument xmlDoc)
public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context)
{
- var bodyParameterDescription = context.BodyParameterDescription;
+ var parameterDescription =
+ context.BodyParameterDescription ??
+ context.FormParameterDescriptions.FirstOrDefault((p) => p is not null);
- if (bodyParameterDescription == null) return;
+ if (parameterDescription is null)
+ {
+ return;
+ }
- var propertyInfo = bodyParameterDescription.PropertyInfo();
- if (propertyInfo != null)
+ var propertyInfo = parameterDescription.PropertyInfo();
+ if (propertyInfo is not null)
{
ApplyPropertyTags(requestBody, context, propertyInfo);
return;
}
- var parameterInfo = bodyParameterDescription.ParameterInfo();
- if (parameterInfo != null)
+ var parameterInfo = parameterDescription.ParameterInfo();
+ if (parameterInfo is not null)
{
ApplyParamTags(requestBody, context, parameterInfo);
- return;
}
}
@@ -39,46 +44,63 @@ private void ApplyPropertyTags(OpenApiRequestBody requestBody, RequestBodyFilter
var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(propertyInfo);
var propertyNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']");
- if (propertyNode == null) return;
+ if (propertyNode is null)
+ {
+ return;
+ }
var summaryNode = propertyNode.SelectSingleNode("summary");
- if (summaryNode != null)
+ if (summaryNode is not null)
+ {
requestBody.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);
+ }
var exampleNode = propertyNode.SelectSingleNode("example");
- if (exampleNode == null) return;
+ if (exampleNode is null || requestBody.Content?.Count is 0)
+ {
+ return;
+ }
+
+ var example = exampleNode.ToString();
foreach (var mediaType in requestBody.Content.Values)
{
- mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, exampleNode.ToString());
+ mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, example);
}
}
private void ApplyParamTags(OpenApiRequestBody requestBody, RequestBodyFilterContext context, ParameterInfo parameterInfo)
{
- if (!(parameterInfo.Member is MethodInfo methodInfo)) return;
+ if (parameterInfo.Member is not MethodInfo methodInfo)
+ {
+ return;
+ }
// If method is from a constructed generic type, look for comments from the generic type method
var targetMethod = methodInfo.DeclaringType.IsConstructedGenericType
? methodInfo.GetUnderlyingGenericTypeMethod()
: methodInfo;
- if (targetMethod == null) return;
+ if (targetMethod is null)
+ {
+ return;
+ }
var methodMemberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(targetMethod);
var paramNode = _xmlNavigator.SelectSingleNode(
$"/doc/members/member[@name='{methodMemberName}']/param[@name='{parameterInfo.Name}']");
- if (paramNode != null)
+ if (paramNode is not null)
{
requestBody.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml);
var example = paramNode.GetAttribute("example", "");
- if (string.IsNullOrEmpty(example)) return;
-
- foreach (var mediaType in requestBody.Content.Values)
+ if (!string.IsNullOrEmpty(example))
{
- mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, example);
+ foreach (var mediaType in requestBody.Content.Values)
+ {
+ mediaType.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, mediaType.Schema, example);
+ }
}
}
}
diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs
index 431b33333c..f41d63ec07 100644
--- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs
+++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs
@@ -1,54 +1,48 @@
-using Swashbuckle.AspNetCore.TestSupport;
-using System;
+using Microsoft.AspNetCore.Mvc;
-namespace Swashbuckle.AspNetCore.SwaggerGen.Test
+namespace Swashbuckle.AspNetCore.SwaggerGen.Test;
+
+///
+/// Summary for FakeControllerWithXmlComments
+///
+/// Description for default response
+public class FakeControllerWithXmlComments
{
///
- /// Summary for FakeControllerWithXmlComments
+ /// Summary for ActionWithSummaryAndRemarksTags
///
- /// Description for default response
- public class FakeControllerWithXmlComments
+ ///
+ /// Remarks for ActionWithSummaryAndRemarksTags
+ ///
+ public void ActionWithSummaryAndRemarksTags()
{
- ///
- /// Summary for ActionWithSummaryAndRemarksTags
- ///
- ///
- /// Remarks for ActionWithSummaryAndRemarksTags
- ///
- public void ActionWithSummaryAndRemarksTags()
- { }
-
- /// Description for param1
- /// Description for param2
- public void ActionWithParamTags(string param1, string param2)
- { }
+ }
+ /// Description for param1
+ /// Description for param2
+ public void ActionWithParamTags(string param1, string param2)
+ {
+ }
+ /// Description for 200 response
+ /// Description for 400 response
+ public void ActionWithResponseTags()
+ {
+ }
- /// Description for 200 response
- /// Description for 400 response
- public void ActionWithResponseTags()
- { }
+ ///
+ /// An action with a JSON body
+ ///
+ /// Parameter from JSON body
+ public void PostBody([FromBody] string name)
+ {
+ }
- /////
- /////
- /////
- /////
- /////
- /////
- /////
- /////
- /////
- //public void ActionWithExampleParams(
- // bool boolParam,
- // int intParam,
- // long longParam,
- // float floatParam,
- // double doubleParam,
- // IntEnum enumParam,
- // Guid guidParam,
- // string stringParam,
- // int badExampleIntParam)
- //{ }
+ ///
+ /// An action with a form body
+ ///
+ /// Parameter from form body
+ public void PostForm([FromForm] string name)
+ {
}
-}
\ No newline at end of file
+}
diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs
index 9d4bd7dabf..ef0b6e43bf 100644
--- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs
+++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs
@@ -1,11 +1,11 @@
-using System.IO;
+using System.Collections.Generic;
+using System.IO;
using System.Xml.XPath;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
-using Xunit;
using Swashbuckle.AspNetCore.TestSupport;
-using System.Collections.Generic;
+using Xunit;
namespace Swashbuckle.AspNetCore.SwaggerGen.Test
{
@@ -109,12 +109,59 @@ public void Apply_SetsDescriptionAndExample_FromUriTypePropertySummaryAndExample
Assert.NotNull(requestBody.Content["application/json"].Example);
Assert.Equal("\"https://test.com/a?b=1&c=2\"", requestBody.Content["application/json"].Example.ToJson());
}
- private XmlCommentsRequestBodyFilter Subject()
+
+ [Fact]
+ public void Apply_SetsDescription_ForParameterFromBody()
+ {
+ var requestBody = new OpenApiRequestBody
+ {
+ Content = new Dictionary
+ {
+ ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } }
+ }
+ };
+ var parameterInfo = typeof(FakeControllerWithXmlComments)
+ .GetMethod(nameof(FakeControllerWithXmlComments.PostBody))
+ .GetParameters()[0];
+ var bodyParameterDescription = new ApiParameterDescription
+ {
+ ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo }
+ };
+ var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null);
+
+ Subject().Apply(requestBody, filterContext);
+
+ Assert.Equal("Parameter from JSON body", requestBody.Description);
+ }
+
+ [Fact]
+ public void Apply_SetsDescription_ForParameterFromForm()
{
- using (var xmlComments = File.OpenText(typeof(FakeControllerWithXmlComments).Assembly.GetName().Name + ".xml"))
+ var requestBody = new OpenApiRequestBody
{
- return new XmlCommentsRequestBodyFilter(new XPathDocument(xmlComments));
- }
+ Content = new Dictionary
+ {
+ ["multipart/form-data"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } }
+ }
+ };
+ var parameterInfo = typeof(FakeControllerWithXmlComments)
+ .GetMethod(nameof(FakeControllerWithXmlComments.PostForm))
+ .GetParameters()[0];
+ var bodyParameterDescription = new ApiParameterDescription
+ {
+ ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo }
+ };
+ var filterContext = new RequestBodyFilterContext(null, [bodyParameterDescription], null, null);
+
+ Subject().Apply(requestBody, filterContext);
+
+ Assert.Equal("Parameter from form body", requestBody.Description);
+ }
+
+ private static XmlCommentsRequestBodyFilter Subject()
+ {
+ using var xmlComments = File.OpenText(typeof(FakeControllerWithXmlComments).Assembly.GetName().Name + ".xml");
+ return new XmlCommentsRequestBodyFilter(new XPathDocument(xmlComments));
}
}
}