Swashbuckle OpenAPI3动态模型无需编译的示例与描述配置问题
问题解答
问题1:能否直接通过OpenAPI规范定义模型,不需要通过C#编译器处理?
完全可以。OpenAPI本身是语言无关的接口描述规范,Swagger/OpenAPIDotNet库原生支持直接操作OpenApiDocument对象的结构,不需要依赖编译后的C#实体类生成Schema。你可以直接构造符合OpenAPI规范的OpenApiSchema对象,添加到文档的Components.Schemas节点即可,完全可以替换掉动态编译C#类的方案。
问题2:如何在IDocumentFilter中通过Schema/Paths节点实现示例和描述的展示?
你可以直接在Apply方法中注释的//Add Schema components位置,遍历你从JSON文件读取的所有模型元数据,手动构造OpenApiSchema对象并赋值描述、示例属性,再加入到全局Schema集合中即可。如果需要关联到具体接口的请求/响应,直接修改Paths节点下对应操作的请求体、响应体的Schema引用即可。
以下是完整的补充代码示例:
public void Apply(OpenApiDocument document, DocumentFilterContext context) { // 原有代码保持不变 if (document.Info.Extensions == null || !document.Info.Extensions.ContainsKey(SwaggerEndpoint.ExtensionDocName)) return; var openIdString = document.Info.Extensions[SwaggerEndpoint.ExtensionDocName] as OpenApiString; if (openIdString == null) return; var docName = openIdString.Value; SwaggerEndpoint endpoint = _swaggerDocument.SwaggerEndpoints.SingleOrDefault(x => x.Name == docName); if (endpoint == null) return; document.Servers = endpoint.ServerObjects; document.Tags = endpoint.Tags; var pathsObjects = _swaggerDocument.GetPathsObject(docName, context); if (pathsObjects.IsValid()) { pathsObjects.ToList().ForEach( item => document.Paths.Add(item.Key, item.Value) ); } // ========== 以下为新增代码 ========== // 初始化Components和Schemas节点 document.Components ??= new OpenApiComponents(); document.Components.Schemas ??= new Dictionary<string, OpenApiSchema>(); // 这里替换为你从JSON读取的模型集合 var allModels = Models; foreach (var model in allModels) { var modelSchema = new OpenApiSchema { Type = "object", // 如果有模型级别的描述可以在此赋值 Description = model.Data?.Description, Properties = new Dictionary<string, OpenApiSchema>() }; foreach (var p in model.Data.Properties) { if (p.Obsoleted) continue; var propertySchema = new OpenApiSchema(); // 处理属性类型 if (p.Type.Type == "array") { propertySchema.Type = "array"; propertySchema.Items = new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = p.Type.ArrayType.ObjectName } }; } else { // 基础类型映射,可根据你实际用到的类型扩展 propertySchema.Type = p.Type.ObjectName.ToLower() switch { "string" => "string", "int" => "integer", "int32" => "integer", "int64" => "integer", "bool" => "boolean", "boolean" => "boolean", "float" => "number", "double" => "number", "decimal" => "number", // 自定义对象类型 _ => "object" }; // 自定义对象类型添加Schema引用 if (propertySchema.Type == "object" && p.Type.ObjectName != "object") { propertySchema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = p.Type.ObjectName }; } } // 赋值属性描述 if (!string.IsNullOrWhiteSpace(p.Description?.ToString())) { propertySchema.Description = p.Description.ToString(); } // 赋值属性示例,注意要和属性类型匹配 if (!string.IsNullOrWhiteSpace(p.Example?.ToString())) { var exampleValue = p.Example.ToString(); propertySchema.Example = propertySchema.Type switch { "string" => new OpenApiString(exampleValue), "integer" => int.TryParse(exampleValue, out var intVal) ? new OpenApiInteger(intVal) : new OpenApiString(exampleValue), "boolean" => bool.TryParse(exampleValue, out var boolVal) ? new OpenApiBoolean(boolVal) : new OpenApiString(exampleValue), "number" => decimal.TryParse(exampleValue, out var decVal) ? new OpenApiDouble((double)decVal) : new OpenApiString(exampleValue), _ => new OpenApiString(exampleValue) }; } modelSchema.Properties.Add(p.Name, propertySchema); } // 避免重复添加 if (!document.Components.Schemas.ContainsKey(model.Name)) { document.Components.Schemas.Add(model.Name, modelSchema); } } // ========== 如果需要关联到Paths节点的接口,参考以下代码 ========== // 示例:给某个POST接口指定请求体Schema // if (document.Paths.TryGetValue("/api/your/interface/path", out var pathItem)) // { // if (pathItem.Operations.TryGetValue(OperationType.Post, out var postOp)) // { // postOp.RequestBody = new OpenApiRequestBody // { // Content = new Dictionary<string, OpenApiMediaType> // { // ["application/json"] = new OpenApiMediaType // { // Schema = new OpenApiSchema // { // Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "你的模型名称" } // } // } // } // }; // } // } }
注意事项
- 如果你的模型存在循环引用,需要额外处理避免构造Schema时出现死循环
- 基础类型的映射需要根据你实际用到的类型做完整覆盖,避免Schema类型错误
- 示例值的类型要和Schema的Type属性匹配,否则Swagger页面可能出现展示异常
内容的提问来源于stack exchange,提问作者learning...
相关产品推荐
相关产品推荐

