Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwaggerUI not display enum summary description, C# .net core?

I used https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-2.1&tabs=visual-studio#xml-comments to show my classes summaries description in SwaggerUI, it's OK but not show enum summary description !
My startup.cs

services.AddSwaggerGen(c =>
{   
    c.SwaggerDoc("v1", new Info
    {
        Version = "v1",
        Title = "My App-Service",
        Description = "My Description",
    });
    c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"));  
    c.DescribeAllEnumsAsStrings();
});

My enum:

public enum GenderEnum
{
    /// <summary>
    /// Man Description
    /// </summary>
    Man = 1,

    /// <summary>
    /// Woman Description
    /// </summary>
    Woman = 2
}

It shows something like following:
Swagger UI enum

I want to show Man Description and Woman Description in SwaggerUI
like this:

Man = 1, Man Description
Woman = 2,  Woman Description


I'm using Swashbuckle.AspNetCore v4.0.1 package

like image 935
Mohammad Dayyan Avatar asked Nov 13 '18 13:11

Mohammad Dayyan


1 Answers

This solution allows for

  • Show underlying value as well as name/description
  • Handle multiple xml documentation files, but only process docs once.
  • Customization of the layout without code change

Here's the class...

using System;
using System.Collections;
using System.Linq;
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 xmlComments;
        private readonly string assemblyName;

        /// <summary>
        /// Initialize schema filter.
        /// </summary>
        /// <param name="xmlComments">Document containing XML docs for enum members.</param>
        public DescribeEnumMembers(XDocument xmlComments)
        {
            this.xmlComments = xmlComments;
            this.assemblyName = DetermineAssembly(xmlComments);
        }

        /// <summary>
        /// Pre-amble to use before the enum items
        /// </summary>
        public static string Prefix { get; set; } = "<p>Possible values:</p>";

        /// <summary>
        /// Format to use, 0 : value, 1: Name, 2: Description
        /// </summary>
        public static string Format { get; set; } = "<b>{0} - {1}</b>: {2}";

        /// <summary>
        /// Apply this schema filter.
        /// </summary>
        /// <param name="schema">Target schema object.</param>
        /// <param name="context">Schema filter context.</param>
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            var type = context.Type;

            // Only process enums and...
            if (!type.IsEnum)
            {
                return;
            }

            // ...only the comments defined in their origin assembly
            if (type.Assembly.GetName().Name != assemblyName)
            {
                return;
            }
            var sb = new StringBuilder(schema.Description);

            if (!string.IsNullOrEmpty(Prefix))
            {
                sb.AppendLine(Prefix);
            }

            sb.AppendLine("<ul>");

            // TODO: Handle flags better e.g. Hex formatting
            foreach (var name in Enum.GetValues(type))
            {
                // Allows for large enums
                var value = Convert.ToInt64(name);
                var fullName = $"F:{type.FullName}.{name}";

                var description = xmlComments.XPathEvaluate(
                    $"normalize-space(//member[@name = '{fullName}']/summary/text())"
                ) as string;

                sb.AppendLine(string.Format("<li>" + Format + "</li>", value, name, description));
            }

            sb.AppendLine("</ul>");

            schema.Description = sb.ToString();
        }

        private string DetermineAssembly(XDocument doc)
        {
            var name = ((IEnumerable)doc.XPathEvaluate("/doc/assembly")).Cast<XElement>().ToList().FirstOrDefault();
            
            return name?.Value;
        }
    }
}

and utilization...

services.AddSwaggerGen(c =>
{
    ...
    
    // See https://github.com/domaindrivendev/Swashbuckle/issues/86
    var dir = new DirectoryInfo(AppContext.BaseDirectory);
    
    foreach (var fi in dir.EnumerateFiles("*.xml"))
    {
        var doc = XDocument.Load(fi.FullName);
        c.IncludeXmlComments(() => new XPathDocument(doc.CreateReader()), true);
        c.SchemaFilter<DescribeEnumMembers>(doc);
    }
});

This then reports as

enter image description here

like image 113
Paul Hatcher Avatar answered Sep 16 '22 14:09

Paul Hatcher