如何为Swagger示例实现分支逻辑以避免重复定义对象?
问题:如何为Swagger设置分支式示例,避免重复定义相同结构的对象?
我们插入的对象具备灵活性,原因是用户无法确定每个项所需的参数。这给确保Swagger展示前端开发人员所需信息带来了挑战。目前我正在定义一个结构完全一致、仅示例内容不同的对象,是否可以通过类似分支语句的方式设置示例,从而无需重复定义多个相同结构的对象?
当前代码实现:
[HttpPost("getsources")] [ProducesResponseType(typeof(SourceMaterialResponse), StatusCodes.Status200OK)] public ActionResult GetSources([FromBody] FilterSourceInput filters) { .... } public class SourceMaterialResponse { public bool success { get; set; } public string message { get; set; } /// <summary> /// 参数定义数组,格式为"列名": "值" /// </summary> /// <example>"Definition": "商业获取时的供应商名称"</example> public List<Parameter_Definition> parameters { get; set; } /// <summary> /// 来源数组,格式为"列名": "值" /// </summary> /// <example>{ /// "SourceID": "", /// "MaterialID": "", /// "Comments": "航空领域最常用的铝材", /// "CeramicOrGlassReinforced": "", /// "CeramicOrGlassComposition": "", /// "PlasticElastomer": "", /// "MaterialDescription": "这是一种以铜为主要合金元素的铝合金", /// "PlasticComposition": "", /// "OrganicPolymerCompositeCoreForm": "", /// "NaturalType": "", /// "OrganicPolymerCompositeMatrix": "", /// "MaterialName": "Susan Alloy", /// "MaterialClassOrType": "Metal", /// "OrganicPolymerCompositeFiber": "", /// "OrganicPolymerCompositeCore": "", /// "MetalCompositionOrAlloy": "Copper" /// }</example> public List<Dictionary<string, string>> items { get; set; } }
解决方案
可以通过自定义Swagger过滤器或扩展包实现动态示例切换,无需重复定义相同结构的对象,以下是两种实用方案:
方案1:自定义IOperationFilter实现动态示例
通过实现Swashbuckle的IOperationFilter接口,根据请求参数(如FilterSourceInput的字段值)动态替换Swagger响应示例。
步骤1:编写自定义过滤器
public class SourceMaterialResponseExampleFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { // 获取请求中的FilterSourceInput参数元数据 var filterParam = context.ApiDescription.ParameterDescriptions .FirstOrDefault(p => p.ParameterType == typeof(FilterSourceInput)); if (filterParam == null) return; // 根据过滤器参数生成对应示例 var responseExample = new OpenApiObject(); // 这里从请求体解析参数,也可根据Query参数判断 var filterModel = context.HttpContext.Request.Body.ReadFromJsonAsync<FilterSourceInput>().Result; var materialType = filterModel?.MaterialClassOrType; if (!string.IsNullOrEmpty(materialType) && materialType.Equals("Metal", StringComparison.OrdinalIgnoreCase)) { // 金属材料示例 responseExample["success"] = new OpenApiBoolean(true); responseExample["message"] = new OpenApiString("成功获取金属材料源"); responseExample["parameters"] = new OpenApiArray { new OpenApiObject { ["Definition"] = new OpenApiString("商业获取时的供应商名称") } }; responseExample["items"] = new OpenApiArray { new OpenApiObject { ["SourceID"] = new OpenApiString("M001"), ["MaterialName"] = new OpenApiString("Susan Alloy"), ["MaterialClassOrType"] = new OpenApiString("Metal"), ["MetalCompositionOrAlloy"] = new OpenApiString("Copper"), ["MaterialDescription"] = new OpenApiString("以铜为主要合金元素的铝合金,广泛应用于航空领域") } }; } else if (!string.IsNullOrEmpty(materialType) && materialType.Equals("Plastic", StringComparison.OrdinalIgnoreCase)) { // 塑料材料示例 responseExample["success"] = new OpenApiBoolean(true); responseExample["message"] = new OpenApiString("成功获取塑料材料源"); responseExample["parameters"] = new OpenApiArray { new OpenApiObject { ["Definition"] = new OpenApiString("塑料材料的成分说明") } }; responseExample["items"] = new OpenApiArray { new OpenApiObject { ["SourceID"] = new OpenApiString("P001"), ["MaterialName"] = new OpenApiString("航空级PC塑料"), ["MaterialClassOrType"] = new OpenApiString("Plastic"), ["PlasticComposition"] = new OpenApiString("聚碳酸酯"), ["MaterialDescription"] = new OpenApiString("高强度耐冲击工程塑料,适用于航空内饰部件") } }; } else { // 默认示例 responseExample["success"] = new OpenApiBoolean(true); responseExample["message"] = new OpenApiString("成功获取材料源"); responseExample["parameters"] = new OpenApiArray(); responseExample["items"] = new OpenApiArray(); } // 更新200响应的示例 if (operation.Responses.TryGetValue("200", out var response)) { response.Content["application/json"].Example = responseExample; } } }
步骤2:注册过滤器
在Program.cs或Startup.cs中注册该过滤器:
builder.Services.AddSwaggerGen(c => { c.OperationFilter<SourceMaterialResponseExampleFilter>(); // 其他Swagger配置(如读取XML注释) });
方案2:使用Swashbuckle.AspNetCore.Filters包简化示例管理
通过第三方包Swashbuckle.AspNetCore.Filters可以更便捷地定义多组示例,再结合过滤器动态切换。
步骤1:安装包
Install-Package Swashbuckle.AspNetCore.Filters
步骤2:定义示例类
public class MetalSourceExample : IExamplesProvider<SourceMaterialResponse> { public SourceMaterialResponse GetExamples() { return new SourceMaterialResponse { success = true, message = "成功获取金属材料源", parameters = new List<Parameter_Definition> { new() { Definition = "商业获取时的供应商名称" } }, items = new List<Dictionary<string, string>> { new() { ["SourceID"] = "M001", ["MaterialName"] = "Susan Alloy", ["MaterialClassOrType"] = "Metal", ["MetalCompositionOrAlloy"] = "Copper", ["MaterialDescription"] = "航空领域最常用的铝合金之一" } } }; } } public class PlasticSourceExample : IExamplesProvider<SourceMaterialResponse> { public SourceMaterialResponse GetExamples() { return new SourceMaterialResponse { success = true, message = "成功获取塑料材料源", parameters = new List<Parameter_Definition> { new() { Definition = "塑料材料成分说明" } }, items = new List<Dictionary<string, string>> { new() { ["SourceID"] = "P001", ["MaterialName"] = "航空级PC塑料", ["MaterialClassOrType"] = "Plastic", ["PlasticComposition"] = "聚碳酸酯", ["MaterialDescription"] = "高强度耐热工程塑料" } } }; } }
步骤3:结合过滤器动态选择示例
复用方案1的过滤器逻辑,在其中根据参数选择对应的示例类生成示例即可。
总结
- 无需重复定义相同结构的对象,只需维护不同的示例数据
- 自定义
IOperationFilter灵活性最高,支持根据任意请求条件切换示例 Swashbuckle.AspNetCore.Filters可简化示例的组织和管理
内容的提问来源于stack exchange,提问作者Susan
相关产品推荐
相关产品推荐

