As of June/2021 OpenApi now supports this and you can extend Swagger to show the details. Here is my code for C# on .NET 5.0.
First define the schema filter in a file (call it DescribeEnumMembers.cs
and be sure to change YourNamespace
to the name of your namespace):
using System;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace YourNamespace
{
/// <summary>
/// Swagger schema filter to modify description of enum types so they
/// show the XML docs attached to each member of the enum.
/// </summary>
public class DescribeEnumMembers: ISchemaFilter
{
private readonly XDocument mXmlComments;
/// <summary>
/// Initialize schema filter.
/// </summary>
/// <param name="argXmlComments">Document containing XML docs for enum members.</param>
public DescribeEnumMembers(XDocument argXmlComments)
=> mXmlComments = argXmlComments;
/// <summary>
/// Apply this schema filter.
/// </summary>
/// <param name="argSchema">Target schema object.</param>
/// <param name="argContext">Schema filter context.</param>
public void Apply(OpenApiSchema argSchema, SchemaFilterContext argContext) {
var EnumType = argContext.Type;
if(!EnumType.IsEnum) return;
var sb = new StringBuilder(argSchema.Description);
sb.AppendLine("<p>Possible values:</p>");
sb.AppendLine("<ul>");
foreach(var EnumMemberName in Enum.GetNames(EnumType)) {
var FullEnumMemberName = $"F:{EnumType.FullName}.{EnumMemberName}";
var EnumMemberDescription = mXmlComments.XPathEvaluate(
$"normalize-space(//member[@name = '{FullEnumMemberName}']/summary/text())"
) as string;
if(string.IsNullOrEmpty(EnumMemberDescription)) continue;
sb.AppendLine($"<li><b>{EnumMemberName}</b>: {EnumMemberDescription}</li>");
}
sb.AppendLine("</ul>");
argSchema.Description = sb.ToString();
}
}
}
Then enable it in your ASP.NET ConfigureServices()
method. Here is my code after snipping out the parts that don't matter for this exercise:
public void ConfigureServices(IServiceCollection argServices) {
// ...<snip other code>
argServices.AddSwaggerGen(SetSwaggerGenOptions);
// ...<snip other code>
return;
// ...<snip other code>
void SetSwaggerGenOptions(SwaggerGenOptions argOptions) {
// ...<snip other code>
AddXmlDocs();
return;
void AddXmlDocs() {
// generate paths for the XML doc files in the assembly's directory.
var XmlDocPaths = Directory.GetFiles(
path: AppDomain.CurrentDomain.BaseDirectory,
searchPattern: "YourAssemblyNameHere*.xml"
);
// load the XML docs for processing.
var XmlDocs = (
from DocPath in XmlDocPaths select XDocument.Load(DocPath)
).ToList();
// ...<snip other code>
// add pre-processed XML docs to Swagger.
foreach(var doc in XmlDocs) {
argOptions.IncludeXmlComments(() => new XPathDocument(doc.CreateReader()), true);
// apply schema filter to add description of enum members.
argOptions.SchemaFilter<DescribeEnumMembers>(doc);
}
}
}
}
Remember to change "YourAssemblyNameHere*.xml"
to match your assembly name. The important line that enables the schema filter is:
argOptions.SchemaFilter<DescribeEnumMembers>(doc);
...which MUST be called AFTER the following line:
argOptions.IncludeXmlComments(() => new XPathDocument(doc.CreateReader()), true);
Using the above code, if you have an enum type defined like this for example:
/// <summary>
/// Setting to control when a no-match report is returned when searching.
/// </summary>
public enum NoMatchReportSetting
{
/// <summary>
/// Return no-match report only if the search query has no match.
/// </summary>
IfNoMatch = 0,
/// <summary>
/// Always return no-match report even if the search query has a match.
/// </summary>
Always = 1,
/// <summary>
/// Never return no-match report even if search query has no match.
/// </summary>
No = 99
}
The Swagger documentation will end up showing a description of each enum member as part of the description of the enum type itself:
