.NET6+NSwag生成OpenApi客户端时复杂类Schema为空问题
.NET6 + NSwag 生成OpenApi客户端时复杂类Schema为空的问题
问题场景
使用最新版NSwag和.NET6创建OpenApi客户端时,ObjectDetail这类复杂类的Schema在生成的swagger.json中为空,旧版本无此问题。相关代码如下:
ObjectDetail类
public class ObjectDetail : ObjectInfo { public IDictionary<int, string> Descriptions; public ObjectStatus Status; public Dictionary<string, ParamRecItem> ParamRec; public Dictionary<string, StatusRecItem> StatusRec; public ObjectDetail() { Descriptions = new Dictionary<int, string>(); ParamRec = new Dictionary<string, ParamRecItem>(); StatusRec = new Dictionary<string, StatusRecItem>(); } }
基类ObjectInfo
public class ObjectInfo { [JsonRequired] public int Id; [JsonRequired] public int No; public int? ParentId; public string Path; public string Name; public string Description; public string Info; public ClassInfo Class; public PlcInfo Plc; }
API控制器代码
// [ApiLogging] [HttpGet] [Route("[controller]_getObjectDetailByName/{name}")] [ProducesResponseType(typeof(ObjectDetail), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public ActionResult GetObjectDetailByName(string name) { ObjectDetail result = scadaService.GetObjectDetailByName(name); return result == null ? BadRequest() : Ok(result); }
生成的swagger.json中对应的Schema
"ObjectDetail": { "type": "object", "additionalProperties": false }
Program.cs配置
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();
原因分析
核心原因是Swagger/NSwag默认只识别类的属性(Property),而代码中使用的是字段(Field)。新版本的NSwag或Swashbuckle.AspNetCore(.NET6默认依赖组件)对成员识别规则更严格,仅暴露属性,不会自动包含字段,导致Schema中无对应成员信息。
解决方法
有两种可行方案:
方案1:将字段改为属性
这是.NET推荐编码规范,也是最稳妥的方式,把类中的字段替换为带get/set的属性:
修改ObjectDetail类:
public class ObjectDetail : ObjectInfo { public IDictionary<int, string> Descriptions { get; set; } public ObjectStatus Status { get; set; } public Dictionary<string, ParamRecItem> ParamRec { get; set; } public Dictionary<string, StatusRecItem> StatusRec { get; set; } public ObjectDetail() { Descriptions = new Dictionary<int, string>(); ParamRec = new Dictionary<string, ParamRecItem>(); StatusRec = new Dictionary<string, StatusRecItem>(); } }
修改基类ObjectInfo:
public class ObjectInfo { [JsonRequired] public int Id { get; set; } [JsonRequired] public int No { get; set; } public int? ParentId { get; set; } public string Path { get; set; } public string Name { get; set; } public string Description { get; set; } public string Info { get; set; } public ClassInfo Class { get; set; } public PlcInfo Plc { get; set; } }
方案2:配置SwaggerGen包含字段
若不想修改现有代码结构,可在Program.cs中配置SwaggerGen,让它识别并包含类的字段:
builder.Services.AddSwaggerGen(options => { // 添加配置,让Swagger包含字段 options.SchemaFilter<IncludeFieldsSchemaFilter>(); }); // 定义SchemaFilter类 public class IncludeFieldsSchemaFilter : ISchemaFilter { public void Apply(OpenApiSchema schema, SchemaFilterContext context) { if (schema.Properties == null) schema.Properties = new Dictionary<string, OpenApiSchema>(); // 获取所有非静态公共字段 var fields = context.Type.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { var propertySchema = context.SchemaGenerator.GenerateSchema(field.FieldType, context.SchemaRepository); // 标记带JsonRequired特性的字段为必填 if (field.GetCustomAttributes(typeof(JsonRequiredAttribute), inherit: true).Any()) { schema.Required.Add(field.Name); } schema.Properties[field.Name] = propertySchema; } } }
注:使用此方案时,需确保ObjectStatus、ParamRecItem等依赖类也符合识别规则(要么是属性,要么被该过滤器处理)。
内容的提问来源于stack exchange,提问作者Andre Fritzsche
相关产品推荐
相关产品推荐

