Azure Function OpenApi规范下生成带OneOf标识的具体类问题咨询
实现方案
以下方案基于微软官方Microsoft.Azure.WebJobs.Extensions.OpenApi包扩展实现,无需依赖停止维护的社区适配包,通过自定义过滤器完成OneOf规则注入。
前置依赖
先安装官方NuGet包:
- 进程内模型:
Microsoft.Azure.WebJobs.Extensions.OpenApi - 隔离工作进程模型:
Microsoft.Azure.Functions.Worker.Extensions.OpenApi
步骤1:自定义OneOf标记属性
用于标注需要生成多态结构的接口属性,指定实现类和鉴别器字段:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class OneOfAttribute : Attribute { /// <summary> /// 鉴别器属性名 /// </summary> public string DiscriminatorProperty { get; } /// <summary> /// 接口的所有实现类类型 /// </summary> public Type[] ImplementTypes { get; } public OneOfAttribute(string discriminatorProperty, params Type[] implementTypes) { DiscriminatorProperty = discriminatorProperty; ImplementTypes = implementTypes; } }
给你的返回类属性标记该特性:
public class PersonResponse { public string Id { get; set; } // 如果需要数组格式,把属性改为IPersonData[] Data即可 [OneOf(nameof(IPersonData.PersonType), typeof(PersonA), typeof(PersonB))] public IPersonData Data { get; set; } }
步骤2:实现自定义Schema过滤器
通过OpenApi的扩展点ISchemaFilter注入OneOf规则:
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions; using Microsoft.OpenApi.Models; using System.Reflection; public class OneOfSchemaFilter : ISchemaFilter { public void Apply(OpenApiSchema schema, SchemaFilterContext context) { if (context.MemberInfo is not PropertyInfo propInfo) return; var oneOfAttr = propInfo.GetCustomAttribute<OneOfAttribute>(); if (oneOfAttr == null) return; // 如果是集合类型,按你期望的数组格式生成 var propType = propInfo.PropertyType; bool isCollection = propType.IsArray || (propType.IsGenericType && typeof(IEnumerable<>).IsAssignableFrom(propType.GetGenericTypeDefinition())); if (isCollection) { schema.Type = "array"; schema.Items = new OpenApiSchema { OneOf = new List<OpenApiSchema>(), Discriminator = new OpenApiDiscriminator { PropertyName = oneOfAttr.DiscriminatorProperty } }; foreach (var implType in oneOfAttr.ImplementTypes) { var implSchema = context.SchemaGenerator.GenerateSchema(implType, context.SchemaRepository); schema.Items.OneOf.Add(new OpenApiSchema { Reference = implSchema.Reference }); if (!context.SchemaRepository.Schemas.ContainsKey(implType.Name)) { context.SchemaRepository.Schemas.Add(implType.Name, implSchema); } } } // 单个对象场景 else { schema.Type = "object"; schema.OneOf = new List<OpenApiSchema>(); schema.Discriminator = new OpenApiDiscriminator { PropertyName = oneOfAttr.DiscriminatorProperty }; foreach (var implType in oneOfAttr.ImplementTypes) { var implSchema = context.SchemaGenerator.GenerateSchema(implType, context.SchemaRepository); schema.OneOf.Add(new OpenApiSchema { Reference = implSchema.Reference }); if (!context.SchemaRepository.Schemas.ContainsKey(implType.Name)) { context.SchemaRepository.Schemas.Add(implType.Name, implSchema); } } } } }
步骤3:注册过滤器到OpenApi配置
进程内Azure Functions
在Startup类中注册:
public override void Configure(IFunctionsHostBuilder builder) { builder.Services.AddSingleton<ISchemaFilter, OneOfSchemaFilter>(); builder.AddOpenApi(options => { options.Version = "0.1"; options.Title = "API"; }); }
隔离工作进程Azure Functions
在Program.cs中注册:
var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() .ConfigureOpenApi() .ConfigureServices(services => { services.AddSingleton<ISchemaFilter, OneOfSchemaFilter>(); }) .Build(); host.Run();
验证生成结果
启动Azure Functions项目后访问OpenApi端点,生成的规范会自动包含你需要的oneOf和discriminator配置,和期望输出完全匹配。
内容的提问来源于stack exchange,提问作者Kyle Eales
相关产品推荐
相关产品推荐

