gpt4 book ai didi

c# - Swagger C# 枚举生成 - 底层 int 值与原始枚举不匹配

转载 作者:行者123 更新时间:2023-12-02 00:27:51 30 4
gpt4 key购买 nike

我在服务器上创建了一个枚举,其中手动设置了整数值,而不是默认从 0 开始递增

public enum UserType
{
Anonymous = 0,
Customer = 10,
Technician = 21,
Manager = 25,
Primary = 30
}

我的服务器正在使用 AspNetCore.App 2.2.0 运行。它在 Startup.cs 中使用 swashbuckle aspnetcore 4.0.1 进行配置,以在每次服务器启动时生成一个 swagger json 文件来描述 api。

然后,我使用 NSwag Studio for windows v 13.2.3.0 生成带有该 swagger JSON 文件的 C Sharp API 客户端,以便在 Xamarin 应用程序中使用。在生成的 c Sharp api 客户端中生成的枚举如下所示 - 底层整数值与原始枚举不匹配。

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.5.0 (Newtonsoft.Json v11.0.0.0)")]
public enum UserType
{
[System.Runtime.Serialization.EnumMember(Value = @"Anonymous")]
Anonymous = 0,

[System.Runtime.Serialization.EnumMember(Value = @"Customer")]
Customer = 1,

[System.Runtime.Serialization.EnumMember(Value = @"Technician")]
Technician = 2,

[System.Runtime.Serialization.EnumMember(Value = @"Manager")]
Manager = 3,

[System.Runtime.Serialization.EnumMember(Value = @"Primary")]
Primary = 4,

}

这给我的客户端带来了一个问题,因为在某些情况下我需要知道整数值。我正在寻找一种解决方案,可以避免每次我想知道客户端的整数值时都编写转换器。

选项 1:NSwag Studio 或 .net 配置(我的 Startup.Cs 配置如下以供引用)中是否缺少一个选项,我可以在其中强制生成的枚举获取与原始枚举相同的整数值?

选项 2:或者,如果没有,我的客户端和服务器都可以通过共享类库访问相同的原始枚举。有没有办法让生成的 api 客户端使用 apiclient.cs 中的实际原始枚举而不是生成自己的枚举?

引用:

Startup.Cs 中我的 swagger 生成代码的枚举部分如下所示

services.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new StringEnumConverter());
....

services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc("v1", new Info { Title = AppConst.SwaggerTitle, Version = "v1" });

setup.UseReferencedDefinitionsForEnums();
... other stuff...
}

最佳答案

@Dawood answer是一部杰作
但它仅适用于旧版本的Swashbuckle(我不确定是哪些版本)
如果您有 Swashbuckle 6.x,该代码将无法编译。
这是相同的解决方案,但适用于 Swashbuckle 6.x

using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

/// <summary>
/// Add enum value descriptions to Swagger
/// https://stackoverflow.com/a/49941775/1910735
/// </summary>
public class EnumDocumentFilter : IDocumentFilter
{
/// <inheritdoc />
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (KeyValuePair<string, OpenApiPathItem> schemaDictionaryItem in swaggerDoc.Paths)
{
OpenApiPathItem schema = schemaDictionaryItem.Value;
foreach (OpenApiParameter property in schema.Parameters)
{
IList<IOpenApiAny> propertyEnums = property.Schema.Enum;
if (propertyEnums.Count > 0)
property.Description += DescribeEnum(propertyEnums);
}
}

if (swaggerDoc.Paths.Count == 0)
return;

// add enum descriptions to input parameters
foreach (OpenApiPathItem pathItem in swaggerDoc.Paths.Values)
{
DescribeEnumParameters(pathItem.Parameters);

foreach (KeyValuePair<OperationType, OpenApiOperation> operation in pathItem.Operations)
DescribeEnumParameters(operation.Value.Parameters);
}
}

private static void DescribeEnumParameters(IList<OpenApiParameter> parameters)
{
if (parameters == null)
return;

foreach (OpenApiParameter param in parameters)
{
if (param.Schema.Enum?.Any() == true)
{
param.Description += DescribeEnum(param.Schema.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)
{
List<string> enumDescriptions = new();
Type? type = null;
foreach (object 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);
}
}
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

//https://stackoverflow.com/a/60276722/4390133
public class EnumFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema is null)
throw new ArgumentNullException(nameof(schema));

if (context is null)
throw new ArgumentNullException(nameof(context));

if (context.Type.IsEnum is false)
return;

schema.Extensions.Add("x-ms-enum", new EnumFilterOpenApiExtension(context));
}
}
using System.Text.Json;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
using Swashbuckle.AspNetCore.SwaggerGen;

public class EnumFilterOpenApiExtension : IOpenApiExtension
{
private readonly SchemaFilterContext _context;
public EnumFilterOpenApiExtension(SchemaFilterContext context)
{
_context = context;
}

public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
{
JsonSerializerOptions options = new() { WriteIndented = true };

var obj = new {
name = _context.Type.Name,
modelAsString = false,
values = _context.Type
.GetEnumValues()
.Cast<object>()
.Distinct()
.Select(value => new { value, name = value.ToString() })
.ToArray()
};
writer.WriteRaw(JsonSerializer.Serialize(obj, options));
}
}
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

/// <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(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema is null)
throw new ArgumentNullException(nameof(schema));

if (context is null)
throw new ArgumentNullException(nameof(context));

if (context.Type.IsEnum)
schema.Extensions.Add("x-enumNames", new NSwagEnumOpenApiExtension(context));
}
}
using System.Text.Json;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
using Swashbuckle.AspNetCore.SwaggerGen;

public class NSwagEnumOpenApiExtension : IOpenApiExtension
{
private readonly SchemaFilterContext _context;
public NSwagEnumOpenApiExtension(SchemaFilterContext context)
{
_context = context;
}

public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
{
string[] enums = Enum.GetNames(_context.Type);
JsonSerializerOptions options = new() { WriteIndented = true };
string value = JsonSerializer.Serialize(enums, options);
writer.WriteRaw(value);
}
}

最后一件事,过滤器的注册

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>();
});

注释

  1. 我正在使用 C# 10 功能(隐式使用和其他)如果您不使用 C# 10,那么您必须添加一些 using 语句并恢复到旧的命名空间样式,并为了 C# 进行一些其他小修改
  2. 我测试了这段代码,结果与原始答案相同

关于c# - Swagger C# 枚举生成 - 底层 int 值与原始枚举不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60222469/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com