Swagger Swashbuckle Asp.NET Core: show details about every enum is used
we can see only default value and no way to see available list of enum
(names and values). I would like to show it. How to do it?
To display the enums as strings in swagger, you configure the JsonStringEnumConverter, adding the following line in ConfigureServices :
services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
The output as below:
If you want to display the enums as stings and int values, you could try to create a EnumSchemaFilter to change the schema. code as below:
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
Enum.GetNames(context.Type)
.ToList()
.ForEach(name => model.Enum.Add(new OpenApiString($"{Convert.ToInt64(Enum.Parse(context.Type, name))} = {name}")));
}
}
}
Configure the SwaggerGen to use above ShemaFilter.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API",
Description = "A simple example ASP.NET Core Web API",
TermsOfService = new Uri("https://example.com/terms"),
Contact = new OpenApiContact
{
Name = "Shayne Boyer",
Email = string.Empty,
Url = new Uri("https://twitter.com/spboyer"),
},
License = new OpenApiLicense
{
Name = "Use under LICX",
Url = new Uri("https://example.com/license"),
}
});
c.SchemaFilter<EnumSchemaFilter>();
});
The result like this:
Swagger enum with names
services
.AddControllers()
.AddJsonOptions(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()));
Show Enum member friendly name on Swagger dropdown and json
I came up with a hack here. It may not necessarily be the solution for you however if you can make it work then I'm happy I could help.
Ended up changing the enum format to string instead of default dropdown. This way I could send asc/desc values to the api. Swagger accepted the values and didnt throw validation errors. And the converter I wrote on the .net core api was also able to convert them nicely.
c.MapType<SortDirectionType>(() => new Schema { Type = "string", Format = "string" });
In addition to this, you may also want to disable default behavior of asp.net core 2.2 validation that kicks in automatically. Not sure why they chose to set that as default behavior.
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
Swagger C# Enum generation - underlying int values do not match the original enum
So these are the two Enum Helpers I'm using. One is used by NSwag (x-enumNames
) and the other is used by Azure AutoRest (x-ms-enums
)
Finally found the reference for EnumDocumentFilter
(https://stackoverflow.com/a/49941775/1910735)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SwaggerDocsHelpers
{
/// <summary>
/// Add enum value descriptions to Swagger
/// https://stackoverflow.com/a/49941775/1910735
/// </summary>
public class EnumDocumentFilter : IDocumentFilter
{
/// <inheritdoc />
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var schemaDictionaryItem in swaggerDoc.Definitions)
{
var schema = schemaDictionaryItem.Value;
foreach (var propertyDictionaryItem in schema.Properties)
{
var property = propertyDictionaryItem.Value;
var propertyEnums = property.Enum;
if (propertyEnums != null && propertyEnums.Count > 0)
{
property.Description += DescribeEnum(propertyEnums);
}
}
}
if (swaggerDoc.Paths.Count <= 0) return;
// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Parameters);
// head, patch, options, delete left out
var possibleParameterisedOperations = new List<Operation> { pathItem.Get, pathItem.Post, pathItem.Put };
possibleParameterisedOperations.FindAll(x => x != null)
.ForEach(x => DescribeEnumParameters(x.Parameters));
}
}
private static void DescribeEnumParameters(IList<IParameter> parameters)
{
if (parameters == null) return;
foreach (var param in parameters)
{
if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true)
{
param.Description += DescribeEnum(nbParam.Enum);
}
else if (param.Extensions.ContainsKey("enum") && param.Extensions["enum"] is IList<object> paramEnums &&
paramEnums.Count > 0)
{
param.Description += DescribeEnum(paramEnums);
}
}
}
private static string DescribeEnum(IEnumerable<object> enums)
{
var enumDescriptions = new List<string>();
Type type = null;
foreach (var enumOption in enums)
{
if (type == null) type = enumOption.GetType();
enumDescriptions.Add($"{Convert.ChangeType(enumOption, type.GetEnumUnderlyingType())} = {Enum.GetName(type, enumOption)}");
}
return $"{Environment.NewLine}{string.Join(Environment.NewLine, enumDescriptions)}";
}
}
public class EnumFilter : ISchemaFilter
{
public void Apply(Schema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");
if (context == null)
throw new ArgumentNullException("context");
if (context.SystemType.IsEnum)
{
var enumUnderlyingType = context.SystemType.GetEnumUnderlyingType();
model.Extensions.Add("x-ms-enum", new
{
name = context.SystemType.Name,
modelAsString = false,
values = context.SystemType
.GetEnumValues()
.Cast<object>()
.Distinct()
.Select(value =>
{
//var t = context.SystemType;
//var convereted = Convert.ChangeType(value, enumUnderlyingType);
//return new { value = convereted, name = value.ToString() };
return new { value = value, name = value.ToString() };
})
.ToArray()
});
}
}
}
/// <summary>
/// Adds extra schema details for an enum in the swagger.json i.e. x-enumNames (used by NSwag to generate Enums for C# client)
/// https://github.com/RicoSuter/NSwag/issues/1234
/// </summary>
public class NSwagEnumExtensionSchemaFilter : ISchemaFilter
{
public void Apply(Schema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");
if (context == null)
throw new ArgumentNullException("context");
if (context.SystemType.IsEnum)
{
var names = Enum.GetNames(context.SystemType);
model.Extensions.Add("x-enumNames", names);
}
}
}
}
Then in your startup.cs you configure them
services.AddSwaggerGen(c =>
{
... the rest of your configuration
// REMOVE THIS to use Integers for Enums
// c.DescribeAllEnumsAsStrings();
// add enum generators based on whichever code generators you decide
c.SchemaFilter<NSwagEnumExtensionSchemaFilter>();
c.SchemaFilter<EnumFilter>();
});
This should generate your enums as this in the Swagger.json file
sensorType: {
format: "int32",
enum: [
0,
1,
2,
3
],
type: "integer",
x-enumNames: [
"NotSpecified",
"Temperature",
"Fuel",
"Axle"
],
x-ms-enum: {
name: "SensorTypesEnum",
modelAsString: false,
values: [{
value: 0,
name: "NotSpecified"
},
{
value: 1,
name: "Temperature"
},
{
value: 2,
name: "Fuel"
},
{
value: 3,
name: "Axle"
}
]
}
},
There is one issue with this solution though, (which I haven't had time to look into)
Is that the Enum names are generated with my DTO names in NSwag - If you do find a solution to this do let me know :-)
Example, the following Enum was generated using NSwag:
Related Topics
Biginteger to Hex/Decimal/Octal/Binary Strings
Calling a Static Method on a Generic Type Parameter
Setting Generic Type at Runtime
Understanding Wcf Windows Authentication
How to Sort a Two-Dimensional (Rectangular) Array in C#
Determine the File Type Using C#
C# Httpwebrequest Command to Get Directory Listing
Passing an Empty Array as Default Value of an Optional Parameter
Variable Declaration in a C# Switch Statement
Use the Long Reserved Word as a Variable Name in C#
System.Text.JSON: How to Specify a Custom Name for an Enum Value
Reading a File Used by Another Process
Firefox Browser Does Not Reload the Update CSS/Js Files
Specified Argument Was Out of the Range of Valid Values. Parameter Name: Site