[英]Swagger UI Web Api documentation Present enums as strings?
有沒有辦法將所有枚舉顯示為 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
}
從文檔:
httpConfiguration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "A title for your API");
c.DescribeAllEnumsAsStrings(); // this will do the trick
});
此外,如果您只想在特定類型和屬性上使用此行為,請使用 StringEnumConverter:
public class Letter
{
[Required]
public string Content {get; set;}
[Required]
[EnumDataType(typeof(Priority))]
[JsonConverter(typeof(StringEnumConverter))]
public Priority Priority {get; set;}
}
你還需要這個包:
Swashbuckle.AspNetCore.Newtonsoft
這在你的啟動中:
services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs to be placed after AddSwaggerGen()
這里有文檔: https ://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft
在 Startup.cs/ConfigureServices() 中:
services
.AddControllersWithViews(...) // or AddControllers() in a Web API
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
安裝Swashbuckle.AspNetCore.Newtonsoft
包。
在 Startup.cs/ConfigureServices() 中:
services
.AddControllersWithViews(...)
.AddNewtonsoftJson(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()));
// order is vital, this *must* be called *after* AddNewtonsoftJson()
services.AddSwaggerGenNewtonsoftSupport();
在 Startup.cs/ConfigureServices() 中:
services
.AddMvc(...)
.AddJsonOptions(options =>
options.SerializerSettings.Converters.Add(new StringEnumConverter()));
httpConfiguration
.EnableSwagger(c =>
{
c.DescribeAllEnumsAsStrings();
});
所以我想我也有類似的問題。 我正在尋找 swagger 來生成枚舉以及 int -> 字符串映射。 API 必須接受 int。 swagger-ui 沒那么重要,我真正想要的是代碼生成在另一邊有一個“真正的”枚舉(在這種情況下,android 應用程序使用改造)。
所以從我的研究來看,這最終似乎是 Swagger 使用的 OpenAPI 規范的一個限制。 無法為枚舉指定名稱和編號。
我發現要遵循的最佳問題是https://github.com/OAI/OpenAPI-Specification/issues/681看起來像“可能很快”,但隨后必須更新 Swagger,在我的情況下 Swashbuckle 為出色地。
現在我的解決方法是實現一個文檔過濾器,它查找枚舉並使用枚舉的內容填充相關描述。
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.DocumentFilter<SwaggerAddEnumDescriptions>();
//disable this
//c.DescribeAllEnumsAsStrings()
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());
}
}
要使用 Newtonsoft JSON 將枚舉生成為字符串,您必須通過添加AddSwaggerGenNewtonsoftSupport()
顯式添加 Newtonsoft 支持,如下所示:
services.AddMvc()
...
.AddNewtonsoftJson(opts =>
{
opts.SerializerSettings.Converters.Add(new StringEnumConverter());
});
services.AddSwaggerGen(...);
services.AddSwaggerGenNewtonsoftSupport(); //
這可以通過一個新包Swashbuckle.AspNetCore.Newtonsoft
獲得。 看起來除了枚舉轉換器支持之外,如果沒有這個包,其他一切都可以正常工作。
.NET CORE 3.1 和 SWAGGER 5
如果您需要一個簡單的解決方案來選擇性地將枚舉作為字符串傳遞:
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MyEnum
{
A, B
}
注意,我們使用System.Text.Json.Serialization
命名空間,而不是Newtonsoft.Json
!
我想在 .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)}";
}
}
然后將其添加到 Startup.cs 中的ConfigureServices
方法中:
c.DocumentFilter<EnumDocumentFilter>();
如果有人有興趣,我已經修改了代碼以使用
.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 (IOpenApiAny enumOption in enums)
{
if (enumOption is OpenApiString @string)
{
string enumString = @string.Value;
enumDescriptions.Add(string.Format("{0} = {1}", (int)Enum.Parse(enumType, enumString), enumString));
}
else if (enumOption is OpenApiInteger integer)
{
int enumInt = integer.Value;
enumDescriptions.Add(string.Format("{0} = {1}", enumInt, Enum.GetName(enumType, enumInt)));
}
}
return string.Join(", ", enumDescriptions.ToArray());
}
}
我的枚舉變量帶有值:
配置服務:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "web server api", Version = "v1" });
c.SchemaFilter<EnumSchemaFilter>();
});
篩選:
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}")));
}
}
}
用 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()));
但似乎 Swashbuckle 版本 5.0.0-rc4 還沒有准備好支持它。 所以我們需要在 Swashbuckle 配置文件中使用一個選項(不推薦使用),直到它像 Newtonsoft 庫一樣支持和反映它。
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.DescribeAllEnumsAsStrings();
此答案與其他答案之間的區別在於僅使用 Microsoft JSON 庫而不是 Newtonsoft。
這對於標准 OpenAPI 是不可能的。 枚舉只用它們的字符串值來描述。
幸運的是,您可以使用客戶端生成器使用的一些非標准擴展來做到這一點。
NSwag 支持x-enumNames
AutoRest 支持x-ms-enum
。
Openapi-generator 支持x-enum-varnames
其他生成器可能支持這些擴展之一或擁有自己的擴展。
要為 NSwag 生成x-enumNames
,請創建以下模式過濾器:
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);
}
}
}
並將其注冊為:
services.AddSwaggerGen(options =>
{
options.SchemaFilter<EnumSchemaFilter>();
});
對於 .NET core 5 ,它與要添加的 .NET core 3.1 相同
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
例子:
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());
});
我在這里找到了很好的解決方法:
@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)));
}
}
}
}
在 Startup.cs 中:
services.AddSwaggerGen(options =>
{
options.SchemaFilter<EnumSchemaFilter>();
}
要在 swagger 中將枚舉顯示為字符串,請通過在 ConfigureServices 中添加以下行來配置 JsonStringEnumConverter:
services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
如果要將枚舉顯示為字符串和 int 值,可以嘗試創建一個 EnumSchemaFilter 來更改架構,如下所示:
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}")));
}
}
}
配置 SwaggerGen 以使用上述 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>();
});
我已經修改了 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());
}
}
使用過濾器添加c.DocumentFilter<SwaggerAddEnumDescriptions>();
在Startup.cs
中招搖配置。
簡單的解決方案。 這個對我有用。
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Priority
{
Low,
Medium,
High
}
在您的 program.cs 中:
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
另請注意:
我剛做了這個,效果很好!
啟動.cs
services.AddSwaggerGen(c => {
c.DescribeAllEnumsAsStrings();
});
模型.cs
public enum ColumnType {
DATE = 0
}
招搖.json
type: {
enum: ["DATE"],
type: "string"
}
我希望這對您有所幫助!
如果您使用的是 newtonsof.json 然后使用這個
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public enum MyEnum
{
A, B
}
如果您使用 System.Text.Json.Serialization
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MyEnum
{
A, B
}
在 .net 核心 3.1 和 swagger 5.0.0 中:
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace WebFramework.Swagger
{
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
var enumValues = schema.Enum.ToArray();
var i = 0;
schema.Enum.Clear();
foreach (var n in Enum.GetNames(context.Type).ToList())
{
schema.Enum.Add(new OpenApiString(n + $" = {((OpenApiPrimitive<int>)enumValues[i]).Value}"));
i++;
}
}
}
}
}
在 Startup.cs 中:
services.AddSwaggerGen(options =>
{
#region EnumDesc
options.SchemaFilter<EnumSchemaFilter>();
#endregion
});
在 Startup.cs 中編寫代碼
services.AddSwaggerGen(c => {
c.DescribeAllEnumsAsStrings();
});
我在我們正在尋找的其他答案中發現了許多缺點,所以我想我會對此提供自己的看法。 我們將 ASP.NET Core 3.1 與 System.Text.Json 結合使用,但我們的方法與使用的 JSON 序列化程序無關。
我們的目標是在 ASP.NET Core API 以及在 Swagger 中記錄相同的文檔時,都接受小寫的枚舉字符串值。 我們目前正在使用[DataContract]
和[EnumMember]
,因此方法是從 EnumMember 值屬性中獲取小寫字母的值並全面使用它。
我們的示例枚舉:
[DataContract]
public class enum Colors
{
[EnumMember(Value="brightPink")]
BrightPink,
[EnumMember(Value="blue")]
Blue
}
我們將通過使用 ISchemaFilter 在 Swashbuckle 中使用 EnumMember 值,如下所示:
public class DescribeEnumMemberValues : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
schema.Enum.Clear();
//Retrieve each of the values decorated with an EnumMember attribute
foreach (var member in context.Type.GetMembers())
{
var memberAttr = member.GetCustomAttributes(typeof(EnumMemberAttribute), false).FirstOrDefault();
if (memberAttr != null)
{
var attr = (EnumMemberAttribute) memberAttr;
schema.Enum.Add(new OpenApiString(attr.Value));
}
}
}
}
}
我們正在使用 第三方 NuGet 包(GitHub repo ) 以確保在 ASP.NET Core 中也使用此命名方案。 在 ConfigureServices 的 Startup.cs 中配置它:
services.AddControllers()
.AddJsonOptions(opt => opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverterWithAttributeSupport()));
最后,我們需要在 Swashbuckle 中注冊我們的 ISchemaFilter,所以還要在 ConfigureServices() 中添加以下內容:
services.AddSwaggerGen(c => {
c.SchemaFilter<DescribeEnumMemberValues>();
});
如果 swagger 的版本是 5.5.x,那么你需要:
安裝:安裝包 Swashbuckle.AspNetCore.Newtonsoft -版本 5.5.0
services.AddSwaggerGenNewtonsoftSupport();
參考: https ://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft
.Net Core 3.0
using Newtonsoft.Json.Converters;
services
.AddMvc(options =>
{
options.EnableEndpointRouting = false;
})
.AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()))
ASP 網絡解決方案
在我的 api 文檔中,一個枚舉仍然顯示為 int,盡管該屬性被標記為StringEnumConverter
。 我們無法為上述所有枚舉使用全局設置。 在 SwaggerConfig 中添加這一行解決了這個問題:
c.MapType<ContactInfoType>(() => new Schema { type = "string", @enum = Enum.GetNames(typeof(ContactInfoType))});
為了生成具有名稱和值的枚舉,您可以使用此解決方案。
先決條件:
注冊 SchemaFilter:
GlobalConfiguration.Configuration
.EnableSwagger("/swagger", c =>
{
c.SchemaFilter<EnumSchemaFilter>();
});
枚舉架構過濾器:
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
var enumProperties = schema.properties?.Where(p => p.Value.@enum != null);
if(enumProperties != null)
{
foreach (var property in enumProperties)
{
var array = Enum.GetNames(type.GetProperty(property.Key).PropertyType).ToArray();
property.Value.vendorExtensions.Add("x-enumNames", array); // NSwag
property.Value.vendorExtensions.Add("x-enum-varnames", array); // Openapi-generator
}
}
}
}
在此處搜索答案后,我找到了在架構中將枚舉顯示為[SomeEnumString = 0, AnotherEnumString = 1]
的問題的部分解決方案,但與此相關的所有答案都只是部分正確,因為@OhWelp在其中之一中提到評論。
這是 .NET core 的完整解決方案(2、3,目前正在開發 6):
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
var names = Enum.GetNames(context.Type).ToList();
names.ForEach(name => model.Enum.Add(new OpenApiString($"{GetEnumIntegerValue(name, context)} = {name}")));
// the missing piece that will make sure that the new schema will not replace the mock value with a wrong value
// this is the default behavior - the first possible enum value as a default "example" value
model.Example = new OpenApiInteger(GetEnumIntegerValue(names.First(), context));
}
}
private int GetEnumIntegerValue(string name, SchemaFilterContext context) => Convert.ToInt32(Enum.Parse(context.Type, name));
}
在啟動/程序中:
services.AddSwaggerGen(options =>
{
options.SchemaFilter<EnumSchemaFilter>();
});
編輯:對代碼進行了一些重構,如果您想查看與其余答案更相似的原始版本,請檢查編輯年表。
帶有 NSwag 和 System.Text.Json 的 In.Net 6 對我有用:
services.AddControllersWithViews()
.AddJsonOptions(o => o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()))
和
services.AddOpenApiDocument(configure =>
{
...
configure.GenerateEnumMappingDescription = true;
});
它接受 int-s 和字符串,在 open-api 和 .ts 客戶端中生成帶有名稱的枚舉,並在 SwaggerUI 中顯示帶有名稱的枚舉
export enum PaymentDirection {
Input = "Input",
Output = "Output",
}
Go 到 Program.cs 並輸入以下代碼:
using Microsoft.AspNetCore.Http.Json;
using MvcJsonOptions = Microsoft.AspNetCore.Mvc.JsonOptions;
.....
builder.Services.Configure<JsonOptions>(o => o.SerializerOptions.Converters.Add(new JsonStringEnumConverter()));
builder.Services.Configure<MvcJsonOptions>(o => o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
我使用基於此處其他答案的以下代碼為 .NET 6 Web API 工作:
1 - 創建文檔過濾器
/// <summary>
/// Add enum value descriptions to Swagger
/// </summary>
public class SwaggerEnumDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var property in swaggerDoc.Components.Schemas)
{
var propertyEnums = property.Value.Enum;
if (propertyEnums is { Count: > 0 })
{
property.Value.Description += DescribeEnum(propertyEnums, property.Key);
}
}
if (swaggerDoc.Paths.Count <= 0)
{
return;
}
// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Parameters);
var affectedOperations = new List<OperationType> { OperationType.Get, OperationType.Post, OperationType.Put, OperationType.Patch };
foreach (var operation in pathItem.Operations)
{
if (affectedOperations.Contains(operation.Key))
{
DescribeEnumParameters(operation.Value.Parameters);
}
}
}
}
private static void DescribeEnumParameters(IList<OpenApiParameter> parameters)
{
if (parameters == null) return;
foreach (var param in parameters)
{
if (param.Schema.Reference != null)
{
var enumType = GetEnumTypeByName(param.Schema.Reference.Id);
var names = Enum.GetNames(enumType).ToList();
param.Description += string.Join(", ", names.Select(name => $"{Convert.ToInt32(Enum.Parse(enumType, name))} - {name}").ToList());
}
}
}
private static 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 static string DescribeEnum(IEnumerable<IOpenApiAny> enums, string propertyTypeName)
{
var enumType = GetEnumTypeByName(propertyTypeName);
if (enumType == null)
{
return null;
}
var parsedEnums = new List<OpenApiInteger>();
foreach (var @enum in enums)
{
if (@enum is OpenApiInteger enumInt)
{
parsedEnums.Add(enumInt);
}
}
return string.Join(", ", parsedEnums.Select(x => $"{x.Value} - {Enum.GetName(enumType, x.Value)}"));
}
}
2 - 將其添加到您的 Program.cs 文件
services.AddSwaggerGen(config =>
{
config.DocumentFilter<SwaggerEnumDocumentFilter>();
})
我在獲得 Swagger 和 .NET 版本 6.x 工作的答案時遇到了一些問題。 我想繼續對枚舉使用整數值,但也顯示可能值的列表(以可讀格式)。 所以這是我的修改版本(包括一些答案的一部分),也許它為你們中的一些人節省了一些時間;)
PS 還有一些改進的空間,你還應該檢查“GetEnumTypeByName”方法的邏輯是否適合你。 就我而言,我想主要只更新項目內部和唯一枚舉的描述。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Models.Api;
using Swashbuckle.AspNetCore.SwaggerGen;
/// <summary>
/// Add enum value descriptions to Swagger
/// </summary>
public class SwaggerEnumDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add enum descriptions to result models
foreach (var property in swaggerDoc.Components.Schemas)
{
var propertyEnums = property.Value.Enum;
if (propertyEnums is { Count: > 0 })
{
property.Value.Description += DescribeEnum(propertyEnums, property.Key);
}
}
if (swaggerDoc.Paths.Count <= 0)
{
return;
}
// add enum descriptions to input parameters
foreach (var pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Parameters);
var affectedOperations = new List<OperationType> { OperationType.Get, OperationType.Post, OperationType.Put };
foreach (var operation in pathItem.Operations)
{
if (affectedOperations.Contains(operation.Key))
{
DescribeEnumParameters(operation.Value.Parameters);
}
}
}
}
private static void DescribeEnumParameters(IList<OpenApiParameter> parameters)
{
if (parameters == null) return;
foreach (var param in parameters)
{
if (param.Schema.Reference != null)
{
param.Description += DescribeEnum(param.Schema.Reference.Id);
}
}
}
private static Type GetEnumTypeByName(string enumTypeName)
{
if (string.IsNullOrEmpty(enumTypeName))
{
return null;
}
try
{
var projectNamespaceRoot = "MyProject.";
return AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Single(x => x.FullName != null
&& x.FullName.StartsWith(projectNamespaceRoot)
&& x.Name == enumTypeName);
}
catch (InvalidOperationException _)
{
throw new ApiException($"SwaggerDoc: Can not find a unique Enum for specified typeName '{enumTypeName}'. Please provide a more unique enum name.");
}
}
private static string DescribeEnum(IEnumerable<IOpenApiAny> enums, string propertyTypeName)
{
var enumType = GetEnumTypeByName(propertyTypeName);
if (enumType == null)
{
return null;
}
var parsedEnums = new List<OpenApiInteger>();
foreach (var @enum in enums)
{
if (@enum is OpenApiInteger enumInt)
{
parsedEnums.Add(enumInt);
}
}
return string.Join(", ", parsedEnums.Select(x => $"{x} = {Enum.GetName(enumType, x.Value)}"));
}
}
正如其他人已經提到的,您必須在 Swagger 設置中注冊此過濾器:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
// some configuration
});
options.DocumentFilter<SwaggerEnumDocumentFilter>();
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.