66 c# asp.net-web-api swagger-ui asp.net-web-api2 swashbuckle
有没有办法将所有枚举显示为swagger中的字符串值而不是int值?
我希望能够提交POST操作并根据其字符串值放置枚举,而不必每次都查看枚举.
我试过,DescribeAllEnumsAsStrings但服务器接收字符串而不是枚举值,这不是我们正在寻找的.
有人解决了这个吗?
编辑:
public class Letter
{
[Required]
public string Content {get; set;}
[Required]
[EnumDataType(typeof(Priority))]
public Priority Priority {get; set;}
}
public class LettersController : ApiController
{
[HttpPost]
public IHttpActionResult SendLetter(Letter letter)
{
// Validation not passing when using DescribeEnumsAsStrings
if (!ModelState.IsValid)
return BadRequest("Not valid")
..
}
// In the documentation for this request I want to see the string values of the enum before submitting: Low, Medium, High. Instead of 0, 1, 2
[HttpGet]
public IHttpActionResult GetByPriority (Priority priority)
{
}
}
public enum Priority
{
Low,
Medium,
High
}
Run Code Online (Sandbox Code Playgroud)
Xav*_*ero 169
来自文档:
httpConfiguration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "A title for your API");
c.DescribeAllEnumsAsStrings(); // this will do the trick
});
Run Code Online (Sandbox Code Playgroud)
此外,如果只想对特定类型和属性执行此行为,请使用StringEnumConverter:
public class Letter
{
[Required]
public string Content {get; set;}
[Required]
[EnumDataType(typeof(Priority))]
[JsonConverter(typeof(StringEnumConverter))]
public Priority Priority {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
Ror*_*ory 35
所以我觉得我有类似的问题.我正在寻找swagger来生成枚举以及int - >字符串映射.API必须接受int.swagger-ui更少,我真正想要的是在另一方面使用"真实"枚举的代码生成(在这种情况下使用改进的android应用程序).
因此,根据我的研究,这最终似乎是Swagger使用的OpenAPI规范的限制.无法为枚举指定名称和数字.
我发现最好的问题是https://github.com/OAI/OpenAPI-Specification/issues/681,它看起来像"很快就会",但Swagger必须更新,在我看来是Swashbuckle as好.
目前,我的解决方法是实现一个文档过滤器,用于查找枚举并使用枚举的内容填充相关描述.
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.DocumentFilter<SwaggerAddEnumDescriptions>();
//disable this
//c.DescribeAllEnumsAsStrings()
Run Code Online (Sandbox Code Playgroud)
SwaggerAddEnumDescriptions.cs:
using System;
using System.Web.Http.Description;
using Swashbuckle.Swagger;
using System.Collections.Generic;
public class SwaggerAddEnumDescriptions : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
// add enum descriptions to result models
foreach (KeyValuePair<string, Schema> schemaDictionaryItem in swaggerDoc.definitions)
{
Schema schema = schemaDictionaryItem.Value;
foreach (KeyValuePair<string, Schema> propertyDictionaryItem in schema.properties)
{
Schema property = propertyDictionaryItem.Value;
IList<object> propertyEnums = property.@enum;
if (propertyEnums != null && propertyEnums.Count > 0)
{
property.description += DescribeEnum(propertyEnums);
}
}
}
// add enum descriptions to input parameters
if (swaggerDoc.paths.Count > 0)
{
foreach (PathItem pathItem in swaggerDoc.paths.Values)
{
DescribeEnumParameters(pathItem.parameters);
// head, patch, options, delete left out
List<Operation> possibleParameterisedOperations = new List<Operation> { pathItem.get, pathItem.post, pathItem.put };
possibleParameterisedOperations.FindAll(x => x != null).ForEach(x => DescribeEnumParameters(x.parameters));
}
}
}
private void DescribeEnumParameters(IList<Parameter> parameters)
{
if (parameters != null)
{
foreach (Parameter param in parameters)
{
IList<object> paramEnums = param.@enum;
if (paramEnums != null && paramEnums.Count > 0)
{
param.description += DescribeEnum(paramEnums);
}
}
}
}
private string DescribeEnum(IList<object> enums)
{
List<string> enumDescriptions = new List<string>();
foreach (object enumOption in enums)
{
enumDescriptions.Add(string.Format("{0} = {1}", (int)enumOption, Enum.GetName(enumOption.GetType(), enumOption)));
}
return string.Join(", ", enumDescriptions.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
这会导致你的swagger-ui上出现如下内容,所以至少你可以"看到你在做什么":

Rom*_*kov 35
要使用 Newtonsoft JSON 将枚举生成为字符串,您必须通过添加AddSwaggerGenNewtonsoftSupport()以下内容来显式添加 Newtonsoft 支持:
services.AddMvc()
...
.AddNewtonsoftJson(opts =>
{
opts.SerializerSettings.Converters.Add(new StringEnumConverter());
});
services.AddSwaggerGen(...);
services.AddSwaggerGenNewtonsoftSupport(); //
Run Code Online (Sandbox Code Playgroud)
这可以通过一个新包获得,Swashbuckle.AspNetCore.Newtonsoft. 除了枚举转换器支持之外,看起来没有这个包的其他一切都可以正常工作。
Jul*_*ian 29
在你的program.cs中:
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
Run Code Online (Sandbox Code Playgroud)
另请注意:
Veg*_*ter 24
.NET 核心 3.1 和 SWAGGER 5
如果您需要一个简单的解决方案来选择性地使枚举作为字符串传递:
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MyEnum
{
A, B
}
Run Code Online (Sandbox Code Playgroud)
注意,我们使用System.Text.Json.Serialization命名空间,而不是Newtonsoft.Json!
Gab*_*uci 18
我想在.NET Core应用程序中使用rory_za的答案,但我必须稍微修改它以使其工作.这是我为.NET Core提出的实现.
我也改变它,因此它不假设底层类型int,并在值之间使用新的线条以便于阅读.
/// <summary>
/// Add enum value descriptions to Swagger
/// </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)}";
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其添加到ConfigureServicesStartup.cs中的方法:
c.DocumentFilter<EnumDocumentFilter>();
Run Code Online (Sandbox Code Playgroud)
Hos*_*ani 16
如果有人感兴趣,我已经修改了代码以使用
.NET CORE 3和Swagger V5
public class SwaggerAddEnumDescriptions : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var property in swaggerDoc.Components.Schemas.Where(x => x.Value?.Enum?.Count > 0))
{
IList<IOpenApiAny> propertyEnums = property.Value.Enum;
if (propertyEnums != null && propertyEnums.Count > 0)
{
property.Value.Description += DescribeEnum(propertyEnums, property.Key);
}
}
// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Operations, swaggerDoc);
}
}
private void DescribeEnumParameters(IDictionary<OperationType, OpenApiOperation> operations, OpenApiDocument swaggerDoc)
{
if (operations != null)
{
foreach (var oper in operations)
{
foreach (var param in oper.Value.Parameters)
{
var paramEnum = swaggerDoc.Components.Schemas.FirstOrDefault(x => x.Key == param.Name);
if (paramEnum.Value != null)
{
param.Description += DescribeEnum(paramEnum.Value.Enum, paramEnum.Key);
}
}
}
}
}
private Type GetEnumTypeByName(string enumTypeName)
{
return AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.FirstOrDefault(x => x.Name == enumTypeName);
}
private string DescribeEnum(IList<IOpenApiAny> enums, string proprtyTypeName)
{
List<string> enumDescriptions = new List<string>();
var enumType = GetEnumTypeByName(proprtyTypeName);
if (enumType == null)
return null;
foreach (OpenApiInteger enumOption in enums)
{
int enumInt = enumOption.Value;
enumDescriptions.Add(string.Format("{0} = {1}", enumInt, Enum.GetName(enumType, enumInt)));
}
return string.Join(", ", enumDescriptions.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
小智 12
我的带有值的 enum stings 的变体:
配置服务:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "web server api", Version = "v1" });
c.SchemaFilter<EnumSchemaFilter>();
});
Run Code Online (Sandbox Code Playgroud)
筛选:
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}")));
}
}
}
Run Code Online (Sandbox Code Playgroud)
在Startup.cs / ConfigureServices()中:
services
.AddControllersWithViews(...)
.AddNewtonsoftJson(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()))
Run Code Online (Sandbox Code Playgroud)
这不需要options.DescribeAllEnumsAsStrings()在AddSwaggerGen()中调用。
基本上参见@Bashir的答案:
services
.AddControllersWithViews(...)
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
Run Code Online (Sandbox Code Playgroud)
而且,正如他所描述的,目前确实需要options.DescribeAllEnumsAsStrings()。
在Startup.cs / ConfigureServices()中:
services
.AddMvc(...)
.AddJsonOptions(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()));
Run Code Online (Sandbox Code Playgroud)
这不需要options.DescribeAllEnumsAsStrings()在AddSwaggerGen()中调用。
使用已DescribeAllEnumsAsStrings()接受答案中的方法。
小智 9
简单的解决方案。这个对我有用。
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Priority
{
Low,
Medium,
High
}
Run Code Online (Sandbox Code Playgroud)
小智 7
To display the enums as strings in swagger, please configure the JsonStringEnumConverter by adding the following line in ConfigureServices :
services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
Run Code Online (Sandbox Code Playgroud)
If you want to display the enums as strings and int values, you could try to create an EnumSchemaFilter to change the schema, 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}")));
}
}
}
Run Code Online (Sandbox Code Playgroud)
Configure the SwaggerGen to use the above SchemaFilter :
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>();
});
Run Code Online (Sandbox Code Playgroud)
我已经修改了 Hosam Rehani 的答案,以使用可空枚举和枚举集合。仅当属性的名称与其类型完全相同时,上一个答案也有效。所有这些问题都在下面的代码中得到解决。
它适用于 .net core 3.x 和 swagger 5.x。
在某些情况下,通过不搜索枚举类型两次可能会更有效。
class SwaggerAddEnumDescriptions : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var property in swaggerDoc.Components.Schemas.Where(x => x.Value?.Enum?.Count > 0))
{
IList<IOpenApiAny> propertyEnums = property.Value.Enum;
if (propertyEnums != null && propertyEnums.Count > 0)
{
property.Value.Description += DescribeEnum(propertyEnums, property.Key);
}
}
// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths)
{
DescribeEnumParameters(pathItem.Value.Operations, swaggerDoc, context.ApiDescriptions, pathItem.Key);
}
}
private void DescribeEnumParameters(IDictionary<OperationType, OpenApiOperation> operations, OpenApiDocument swaggerDoc, IEnumerable<ApiDescription> apiDescriptions, string path)
{
path = path.Trim('/');
if (operations != null)
{
var pathDescriptions = apiDescriptions.Where(a => a.RelativePath == path);
foreach (var oper in operations)
{
var operationDescription = pathDescriptions.FirstOrDefault(a => a.HttpMethod.Equals(oper.Key.ToString(), StringComparison.InvariantCultureIgnoreCase));
foreach (var param in oper.Value.Parameters)
{
var parameterDescription = operationDescription.ParameterDescriptions.FirstOrDefault(a => a.Name == param.Name);
if (parameterDescription != null && TryGetEnumType(parameterDescription.Type, out Type enumType))
{
var paramEnum = swaggerDoc.Components.Schemas.FirstOrDefault(x => x.Key == enumType.Name);
if (paramEnum.Value != null)
{
param.Description += DescribeEnum(paramEnum.Value.Enum, paramEnum.Key);
}
}
}
}
}
}
bool TryGetEnumType(Type type, out Type enumType)
{
if (type.IsEnum)
{
enumType = type;
return true;
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null && underlyingType.IsEnum == true)
{
enumType = underlyingType;
return true;
}
}
else
{
Type underlyingType = GetTypeIEnumerableType(type);
if (underlyingType != null && underlyingType.IsEnum)
{
enumType = underlyingType;
return true;
}
else
{
var interfaces = type.GetInterfaces();
foreach (var interfaceType in interfaces)
{
underlyingType = GetTypeIEnumerableType(interfaceType);
if (underlyingType != null && underlyingType.IsEnum)
{
enumType = underlyingType;
return true;
}
}
}
}
enumType = null;
return false;
}
Type GetTypeIEnumerableType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
var underlyingType = type.GetGenericArguments()[0];
if (underlyingType.IsEnum)
{
return underlyingType;
}
}
return null;
}
private Type GetEnumTypeByName(string enumTypeName)
{
return AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.FirstOrDefault(x => x.Name == enumTypeName);
}
private string DescribeEnum(IList<IOpenApiAny> enums, string proprtyTypeName)
{
List<string> enumDescriptions = new List<string>();
var enumType = GetEnumTypeByName(proprtyTypeName);
if (enumType == null)
return null;
foreach (OpenApiInteger enumOption in enums)
{
int enumInt = enumOption.Value;
enumDescriptions.Add(string.Format("{0} = {1}", enumInt, Enum.GetName(enumType, enumInt)));
}
return string.Join(", ", enumDescriptions.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
使用过滤器添加c.DocumentFilter<SwaggerAddEnumDescriptions>();到Startup.cs.
对于 .NET core 5, 它与 .NET core 3.1 相同,添加
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
Run Code Online (Sandbox Code Playgroud)
例子:
services.AddControllers(options =>
{
options.ReturnHttpNotAcceptable = true;
var builder = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();
options.Filters.Add(new AuthorizeFilter(builder.Build()));
}).AddJsonOptions(options =>
{
options.JsonSerializerOptions.IgnoreNullValues = true;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
Run Code Online (Sandbox Code Playgroud)
小智 5
我只是这样做,并且效果很好!
启动文件
services.AddSwaggerGen(c => {
c.DescribeAllEnumsAsStrings();
});
Run Code Online (Sandbox Code Playgroud)
Model.cs
public enum ColumnType {
DATE = 0
}
Run Code Online (Sandbox Code Playgroud)
swagger.json
type: {
enum: ["DATE"],
type: "string"
}
Run Code Online (Sandbox Code Playgroud)
希望对您有所帮助!
使用asp.net核心3
using System.Text.Json.Serialization;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
Run Code Online (Sandbox Code Playgroud)
但是Swashbuckle版本5.0.0-rc4似乎尚未准备好支持该版本。因此,我们需要在Swashbuckle配置文件中使用一个选项(不建议使用),直到它像Newtonsoft库一样支持并反映它。
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.DescribeAllEnumsAsStrings();
Run Code Online (Sandbox Code Playgroud)
此答案与其他答案之间的区别是仅使用Microsoft JSON库而不是Newtonsoft。
小智 5
我在这里找到了很好的解决方法:
@PauloVetor - 使用 ShemaFilter 解决它,如下所示:
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
Enum.GetNames(context.Type)
.ToList()
.ForEach(n => model.Enum.Add(new OpenApiString(n)));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在 Startup.cs 中:
services.AddSwaggerGen(options =>
{
options.SchemaFilter<EnumSchemaFilter>();
}
Run Code Online (Sandbox Code Playgroud)
这在标准 OpenAPI 中是不可能的。枚举只用它们的字符串值来描述。
幸运的是,您可以使用客户端生成器使用的一些非标准扩展来实现。
NSwag 支持 x-enumNames
AutoRest 支持x-ms-enum.
Openapi-generator 支持 x-enum-varnames
其他生成器可能支持这些扩展之一或拥有自己的扩展。
要x-enumNames为 NSwag 创建以下架构过滤器:
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
var array = new OpenApiArray();
array.AddRange(Enum.GetNames(context.Type).Select(n => new OpenApiString(n)));
// NSwag
schema.Extensions.Add("x-enumNames", array);
// Openapi-generator
schema.Extensions.Add("x-enum-varnames", array);
}
}
}
Run Code Online (Sandbox Code Playgroud)
并将其注册为:
services.AddSwaggerGen(options =>
{
options.SchemaFilter<EnumSchemaFilter>();
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
41485 次 |
| 最近记录: |