You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Microsoft.AspNetCore.OpenApi生成指向基础Schema的$ref而非同类型属性

解决Microsoft.AspNetCore.OpenApi生成无效$ref路径的问题

问题场景

你定义了如下C#记录类型:

public record Response
{
    public ImmutableList<TypeA>? Completes { get; init; } = null;
    public ImmutableList<TypeA>? Incompletes { get; init; } = null;

    // 其他类成员
}

使用Microsoft.AspNetCore.OpenApi生成OpenAPI规范时,Incompletes字段的items引用生成了无效路径:

"Response": {
    "type": "object",
    "properties": {
        "Completes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        },
        "Incompletes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/#/properties/Completes/items"
            },
            "nullable": true
        }
    }
}

该路径包含无效的#标记,导致API网关工具无法识别,期望生成的规范中Incompletes的items直接指向TypeA的Schema:

"Response": {
    "type": "object",
    "properties": {
        "Completes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        },
        "Incompletes": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/TypeA"
            },
            "nullable": true
        }
    }
}

当前Startup.cs仅配置了基础的OpenApi生成:

services.AddOpenApi(ConfigureApiGen);

其中ConfigureApiGen仅做文档名称等简单配置。

解决方案

通过自定义Schema过滤器修正无效的引用路径,步骤如下:

1. 创建自定义Schema过滤器

实现ISchemaFilter接口,遍历Schema属性并修正数组项的引用:

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;

public class FixArrayItemReferenceFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        // 仅处理Response类型的Schema
        if (context.Type != typeof(Response)) return;

        // 定位Incompletes属性对应的Schema
        if (schema.Properties.TryGetValue(nameof(Response.Incompletes), out var incompletesSchema) 
            && incompletesSchema.Type == "array")
        {
            // 通过反射获取Incompletes属性的元素类型(TypeA)
            var incompletesProp = context.Type.GetProperty(nameof(Response.Incompletes));
            var itemType = incompletesProp?.PropertyType.GetGenericArguments()[0];
            if (itemType == null) return;

            // 生成元素类型对应的Schema ID
            var schemaId = context.SchemaGenerator.GenerateSchemaId(itemType);
            
            // 替换为正确的引用
            incompletesSchema.Items.Reference = new OpenApiReference
            {
                Type = ReferenceType.Schema,
                Id = schemaId
            };
        }
    }
}

如果只需要针对TypeA做处理,也可以使用简化版本:

public class FixArrayItemReferenceFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        foreach (var property in schema.Properties.Values)
        {
            if (property.Type == "array" && property.Items?.Reference != null)
            {
                // 检测到无效内部引用时替换为TypeA的Schema引用
                if (property.Items.Reference.Id.Contains("#"))
                {
                    property.Items.Reference = new OpenApiReference
                    {
                        Type = ReferenceType.Schema,
                        Id = "TypeA"
                    };
                }
            }
        }
    }
}

2. 注册自定义过滤器

修改ConfigureApiGen方法,添加过滤器注册:

private void ConfigureApiGen(OpenApiGeneratorOptions options)
{
    // 原有文档配置(示例)
    options.AddDocumentTransformer(doc =>
    {
        doc.Info.Title = "你的API文档";
        doc.Info.Version = "v1";
    });

    // 注册自定义Schema过滤器
    options.SchemaFilter<FixArrayItemReferenceFilter>();
}

原理说明

自定义过滤器会在OpenAPI Schema生成过程中拦截处理,针对Response类型的Incompletes属性,将其数组项的无效内部引用替换为直接指向TypeA的Schema引用,确保生成的OpenAPI规范路径符合标准格式,被API网关工具正常识别。

内容的提问来源于stack exchange,提问作者CodingBeagle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:42:09