Currently the <remarks> are only displayed for the controller actions, but not for the parameters.
See [Feature Request] Add remarks to parameters · Issue #1937 · domaindrivendev/Swashbuckle.AspNetCore
... the Swagger/OpenAPI Parameter object only supports a single description field for entering descriptive text. For simplicity, I'd like to maintain a 1:1 mapping between XML Comments tag and Swagger/OpenAPI field as opposed to combining/formatting multiple tags into the one field. So, your request is not something I plan on adding to SB at this point.
But I found out it could be added with custom IParameterFilter
/// <summary>
/// Add the content of <remarks> to the description of a parameter
/// Inspired by <see cref="Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter"/>
/// </summary>
public class AddRemarksToParameterDescription : IParameterFilter
{
private readonly XPathNavigator _xmlNavigator;
public AddRemarksToParameterDescription(XPathDocument xmlDoc)
{
_xmlNavigator = xmlDoc.CreateNavigator()!;
}
public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
{
if (context.PropertyInfo != null)
{
ApplyPropertyTags(parameter, context);
}
else if (context.ParameterInfo != null)
{
ApplyParamTags(parameter, context);
}
}
private void ApplyPropertyTags(OpenApiParameter parameter, ParameterFilterContext context)
{
var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(context.PropertyInfo);
var propertyNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']");
if (propertyNode == null) return;
var remarksNode = propertyNode.SelectSingleNode("remarks");
if (remarksNode != null)
{
parameter.Description += FormatRemarks(remarksNode.InnerXml);
}
}
private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext context)
{
if (!(context.ParameterInfo.Member is MethodInfo methodInfo)) return;
// If method is from a constructed generic type, look for comments from the generic type method
var targetMethod = methodInfo.DeclaringType is { IsConstructedGenericType: true }
? methodInfo.GetUnderlyingGenericTypeMethod()
: methodInfo;
if (targetMethod == null) return;
var methodMemberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(targetMethod);
var paramNode = _xmlNavigator.SelectSingleNode(
$"/doc/members/member[@name='{methodMemberName}']/param[@name='{context.ParameterInfo.Name}']");
if (paramNode != null)
{
var remarksNode = paramNode.SelectSingleNode("remarks");
if (remarksNode != null)
{
parameter.Description += FormatRemarks(remarksNode.InnerXml);
}
}
}
private static string FormatRemarks(string text)
{
return "<br><br>Remarks: <br><i>" + XmlCommentsTextHelper.Humanize(text) + "</i>";
}
}
Add in your setup:
instead of this: (from the official readme)
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo
{
Title = "My API - V1",
Version = "v1"
}
);
var filePath = Path.Combine(System.AppContext.BaseDirectory, "MyApi.xml");
c.IncludeXmlComments(filePath);
});
Do this:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo
{
Title = "My API - V1",
Version = "v1"
}
);
var filePath = Path.Combine(System.AppContext.BaseDirectory, "MyApi.xml");
// ==== NEW
var xmlDox = new XPathDocument(filePath); // Re-use XPathDocument
c.IncludeXmlComments(() => xmlDox); // IncludeXmlComments with current XPathDocument
c.ParameterFilter<AddRemarksToParameterDescription>(xmlDox); // The new filter
});
Tested with Swashbuckle.AspNetCore 5.5 + C# 8 with nullable analysis. I think it should also work with Swashbuckle.AspNetCore 6