I am working with a Swagger API documentation and want to have my description of the enums in the documentation. I am using a custom filter to extract information from classes and enums, using annotations. e.g.:
using System.ComponentModel;
...
[DisplayName("Upload class")] // Works fine
public class Upload
{
[DisplayName("Primary Key")] // Works fine
public int UploadMetaId { get; set; }
[Display(Name = "document name")] // Works fine too
public string Title { get; set; }
}
But I have problems with my Enums:
[DisplayName("Document types")] // Illegal, gives error CS0592
// or
[Display(Name = "Document types")] // Illegal too, gives also CS0592
public enum UploadType
{
[Display(Name = "Årsopgørelse")] // Works fine
PartnerAarsopgoerelse = 1,
[Display(Name = "Ægtefælles årsopgørelse")]
AegtefaelleAarsopgoerelse = 2
}
The error CS0592 says it's not valid on this declaration type.
So what can I use instead?
UPDATE
I am using the following NuGet packages:
Thanks to @ralf and the article in his comment, I created a solution with my own IDocumentFilter.
I hope I can save someone for a lot of searches by using the code below.
I program.cs I pick up the XML documentation from the project and pass relevant 'summary' to the IDocumentFilter:
private static void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(c =>
{
...
Dictionary<string, string> Dict = new Dictionary<string, string>();
var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
foreach (var filePath in System.IO.Directory.GetFiles(dir, "*.xml"))
{
c.IncludeXmlComments(filePath);
GetXMLDoc(filePath, Dict);
}
c.DocumentFilter<SwaggerEnumDocumentFilter>(Dict);
});
}
private static void GetXMLDoc(string path, Dictionary<string,string> Dict)
{
var _xmlComments = new XmlDocument();
var reader = XmlReader.Create(path);
_xmlComments.Load(reader);
var xpath = $"//member[@name[starts-with(.,'F')] or @name[starts-with(.,'T')]]";
var nodes = _xmlComments.DocumentElement.SelectNodes(xpath);
foreach(XmlNode node in nodes)
{
var attribute = node.Attributes["name"];
if (attribute != null)
{
string summary = node.FirstChild.InnerText.Trim(' ','\n');
Dict.Add(attribute.Value, summary);
}
}
}
In the filter I pick up the XML documentation from the passed dictionary:
public class SwaggerEnumDocumentFilter : IDocumentFilter
{
Dictionary<string, string> EnumDescription = new Dictionary<string, string>();
public SwaggerEnumDocumentFilter(Dictionary<string, string> enumDescription)
{
EnumDescription = enumDescription;
}
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions Schemas section in Swagger
foreach (var property in swaggerDoc.Components.Schemas)
{
var propertyEnums = property.Value.Enum;
if (propertyEnums is { Count: > 0 })
{
property.Value.Description += DescribeEnum(property.Key, false);
}
}
if (swaggerDoc.Paths.Count <= 0)
{
return;
}
//add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
foreach (var operation in pathItem.Operations)
{
if (operation.Value.Parameters != null)
{
foreach (var param in operation.Value.Parameters)
{
if (param.Schema.Reference != null)
{
param.Description += DescribeEnum(param.Schema.Reference.Id, true);
}
}
}
}
}
}
private Type GetEnumTypeByName(string enumTypeName)
{
if (string.IsNullOrEmpty(enumTypeName))
{
return null;
}
try
{
return AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Single(x => x.FullName != null && x.Name == enumTypeName);
}
catch (InvalidOperationException e)
{
throw new Exception($"SwaggerDoc: Can not find a unique Enum for specified typeName '{enumTypeName}'. Please provide a more unique enum name.");
}
}
private string DescribeEnum(string propertyTypeName, bool inApiList)
{
var enumType = GetEnumTypeByName(propertyTypeName);
if (enumType == null)
{
return null;
}
var values = Enum.GetValues(enumType);
if (values == null)
{
return null;
}
string result = "<ul>";
if (inApiList)
{
var key = $"T:{enumType.FullName}";
var summary = EnumDescription.ContainsKey(key) ? EnumDescription[key] : "";
result = $"<p>{summary}</p><ul>";
}
foreach (var value in values)
{
var key = $"F:{enumType.FullName}.{value}";
var summary = EnumDescription.ContainsKey(key) ? EnumDescription[key] : "";
string n = EnumUtils.GetDisplayName((System.Enum)value);
result += $"<li>{(int)value} - {n} : {summary} </li>";
}
result += "</ul>";
return result;
}
}