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

加载含外部Schema的OpenAPI文档失败,求无需修改原文档的解决办法

加载缺失Version字段的外部OpenAPI Schema失败的变通方案

问题背景

尝试加载第三方OpenAPI文档时,其引用的外部Schema文件因缺失Version字段导致加载失败,报错信息如下:

[File: schema.json] Version node not found.
Schema unresolved reference: True

原运行代码:

using Microsoft.OpenApi;
using Microsoft.OpenApi.Reader;

namespace Dasfn
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Uri baseUrl = new("https://www.bcb.gov.br/htms/dasfn/catalogo/1.0.10/");

            OpenApiReaderSettings settings = new()
            {
                BaseUrl = baseUrl,
                LoadExternalRefs = true,
            };

            ReadResult readResult = await OpenApiDocument.LoadAsync(new Uri(baseUrl, "openapi.json").AbsoluteUri, settings);

            if (readResult.Diagnostic?.Errors is IList<OpenApiError> errors)
            {
                foreach (OpenApiError error in errors)
                { 
                    Console.WriteLine(error); 
                }
            }

            OpenApiDocument document = readResult.Document!;

            OpenApiSchemaReference schema = (OpenApiSchemaReference) document
                .Paths["/catalogo"]
                .Operations![HttpMethod.Get]
                .Responses!["200"]
                .Content!["application/json"].Schema!
                ;

            Console.WriteLine($"Schema unresolved reference: {schema.UnresolvedReference}");
        }
    }
}

由于无法修改原OpenAPI文档及外部Schema,可通过以下方案解决:


方案1:自定义外部引用解析器,补全Version字段

实现IOpenApiExternalReferenceResolver接口,在加载外部Schema内容时手动添加缺失的Version节点(需匹配原OpenAPI文档的版本,比如原文档用3.0.0则添加对应版本),再交给官方解析器处理。

示例代码:

using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using System.Text.Json;

namespace Dasfn
{
    // 自定义外部引用解析器
    public class CustomSchemaResolver : IOpenApiExternalReferenceResolver
    {
        private readonly OpenApiExternalReferenceResolver _defaultResolver;
        private readonly string _targetOpenApiVersion;

        public CustomSchemaResolver(OpenApiReaderSettings settings, string openApiVersion)
        {
            _defaultResolver = new OpenApiExternalReferenceResolver(settings);
            _targetOpenApiVersion = openApiVersion;
        }

        public async Task<OpenApiDocument> ResolveReferenceAsync(string reference, OpenApiDocument rootDocument, OpenApiReaderSettings settings)
        {
            // 获取远程Schema内容
            using var client = new HttpClient();
            var schemaContent = await client.GetStringAsync(reference);

            // 解析JSON并添加缺失的Version字段
            var jsonDoc = JsonDocument.Parse(schemaContent);
            using var ms = new MemoryStream();
            using var writer = new Utf8JsonWriter(ms);

            writer.WriteStartObject();
            // 添加Version节点
            writer.WriteString("openapi", _targetOpenApiVersion);

            // 复制原Schema的所有内容
            foreach (var property in jsonDoc.RootElement.EnumerateObject())
            {
                property.WriteTo(writer);
            }
            writer.WriteEndObject();
            writer.Flush();
            ms.Seek(0, SeekOrigin.Begin);

            // 用修改后的内容加载文档
            var reader = new OpenApiStreamReader(settings);
            var result = reader.Read(ms, out var diagnostic);
            return result;
        }
    }

    internal class Program
    {
        static async Task Main(string[] args)
        {
            Uri baseUrl = new("https://www.bcb.gov.br/htms/dasfn/catalogo/1.0.10/");
            // 原OpenAPI文档的版本,可从openapi.json中获取,这里假设是3.0.0
            string openApiVersion = "3.0.0";

            OpenApiReaderSettings settings = new()
            {
                BaseUrl = baseUrl,
                LoadExternalRefs = true,
            };

            // 设置自定义解析器
            settings.ExternalReferenceResolver = new CustomSchemaResolver(settings, openApiVersion);

            ReadResult readResult = await OpenApiDocument.LoadAsync(new Uri(baseUrl, "openapi.json").AbsoluteUri, settings);

            if (readResult.Diagnostic?.Errors is IList<OpenApiError> errors)
            {
                foreach (OpenApiError error in errors)
                { 
                    Console.WriteLine(error); 
                }
            }

            OpenApiDocument document = readResult.Document!;

            var schema = document
                .Paths["/catalogo"]
                .Operations![HttpMethod.Get]
                .Responses!["200"]
                .Content!["application/json"].Schema!;

            // 输出是否为未解析引用
            Console.WriteLine($"Is schema reference unresolved: {schema is OpenApiSchemaReference refSchema && refSchema.UnresolvedReference}");
        }
    }
}

方案2:预加载并修改外部Schema,替换文档引用

先下载外部Schema文件,添加Version字段后,手动替换原OpenAPI文档中的外部引用为修改后的Schema内容,再加载文档。

示例代码:

using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using System.Text.Json;

namespace Dasfn
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Uri baseUrl = new("https://www.bcb.gov.br/htms/dasfn/catalogo/1.0.10/");
            string openApiVersion = "3.0.0";

            // 1. 下载并修改外部Schema
            using var client = new HttpClient();
            string schemaContent = await client.GetStringAsync(new Uri(baseUrl, "schema.json"));
            var jsonObj = JsonSerializer.Deserialize<Dictionary<string, object>>(schemaContent)!;
            jsonObj["openapi"] = openApiVersion;
            string modifiedSchemaContent = JsonSerializer.Serialize(jsonObj);

            // 2. 加载原OpenAPI文档(不加载外部引用)
            var readerSettings = new OpenApiReaderSettings { LoadExternalRefs = false };
            var openApiDoc = await OpenApiDocument.LoadAsync(new Uri(baseUrl, "openapi.json").AbsoluteUri, readerSettings);

            // 3. 解析修改后的Schema
            var schemaReader = new OpenApiStringReader();
            var modifiedSchemaDoc = schemaReader.Read(modifiedSchemaContent, out _);
            var targetSchema = modifiedSchemaDoc.Components.Schemas.Values.First(); // 根据实际Schema结构获取目标Schema

            // 4. 替换原文档中的引用
            openApiDoc.Paths["/catalogo"]
                .Operations[HttpMethod.Get]
                .Responses["200"]
                .Content["application/json"].Schema = targetSchema;

            Console.WriteLine("Schema已成功加载,未标记为未解析引用");
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:28:11