如何让Swashbuckle为Guid键字典生成合理的Schema和示例?
解决Swashbuckle对Dictionary<Guid, T>的Schema和示例生成问题
我在开发REST接口时,Swashbuckle能为其他GET请求中的FancyEntity生成正常的JSON示例和Schema,但当GET请求返回Dictionary<Guid, HelloWorldEvent>类型时,生成的示例键是additionalPropN,Schema里键标注为<*>:。我想把示例替换为真实的Guid值,同时让Schema显示为string($uuid)。相关代码如下:
public class HelloWorldController(IUniversalEventService<HelloWorldEvent> service) : BaseEventController<HelloWorldEvent>(service) { /* ... */ [HttpGet(GetAllSchedulesRoute)] [ProducesResponseType<Dictionary<Guid, HelloWorldEvent>>((int)HttpStatusCode.OK)] public override Task<IActionResult> GetAllSchedules(CancellationToken cancel = default) => base.GetAllSchedules(cancel); /* ... */ }
当前生成的示例JSON为:
{ "additionalProp1": { "world": "string", "sendAt": "2024-02-06T12:46:06.301Z" }, "additionalProp2": { "world": "string", "sendAt": "2024-02-06T12:46:06.301Z" }, "additionalProp3": { "world": "string", "sendAt": "2024-02-06T12:46:06.301Z" } }
解决方案
1. 自定义Schema过滤器修正键类型显示
创建一个ISchemaFilter实现类,修改Dictionary<Guid, T>对应的Schema,将键的类型指定为string($uuid)格式:
public class GuidDictionarySchemaFilter : ISchemaFilter { public void Apply(OpenApiSchema schema, SchemaFilterContext context) { // 仅处理Dictionary<Guid, T>类型 if (!context.Type.IsGenericType || context.Type.GetGenericTypeDefinition() != typeof(Dictionary<,>) || context.Type.GetGenericArguments()[0] != typeof(Guid)) { return; } // 配置键为UUID格式的字符串 schema.PatternProperties = new Dictionary<string, OpenApiSchema> { ["^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"] = schema.AdditionalProperties }; // 移除默认的additionalProps描述,改用PatternProperties展示UUID规则 schema.AdditionalPropertiesAllowed = false; schema.Properties.Clear(); } }
在Swagger注册时添加这个过滤器:
builder.Services.AddSwaggerGen(c => { c.SchemaFilter<GuidDictionarySchemaFilter>(); // 其他Swagger配置项 });
2. 自定义示例过滤器生成带Guid键的示例
创建IExampleFilter实现类,生成包含真实Guid值的示例数据:
public class GuidDictionaryExampleFilter : IExampleFilter { public void Apply(OpenApiExample example, ExampleFilterContext context) { // 仅处理Dictionary<Guid, T>类型 if (!context.Type.IsGenericType || context.Type.GetGenericTypeDefinition() != typeof(Dictionary<,>) || context.Type.GetGenericArguments()[0] != typeof(Guid)) { return; } var valueType = context.Type.GetGenericArguments()[1]; // 利用Swashbuckle内置示例生成器创建实体示例 var entityExample = context.SchemaGenerator.GenerateExample(valueType); // 构建带Guid键的字典示例 var exampleDict = new Dictionary<Guid, object> { { Guid.Parse("3fa85f64-5717-4562-b3fc-2c963f66afa6"), entityExample }, { Guid.Parse("7b2d8c0a-1e3f-4a5b-9c7d-8e9f0a1b2c3d"), entityExample } }; example.Value = OpenApiAnyFactory.CreateFromJson( System.Text.Json.JsonSerializer.Serialize(exampleDict) ); } }
注册示例过滤器:
builder.Services.AddSwaggerGen(c => { c.ExampleFilter<GuidDictionaryExampleFilter>(); // 其他Swagger配置项 });
3. 组合使用两个过滤器
将上述两个过滤器同时注册,即可同时实现Schema键类型显示为string($uuid),并生成带真实Guid的示例JSON。
内容的提问来源于stack exchange,提问作者user2015635
相关产品推荐
相关产品推荐

