【问题标题】:How to treat an object implementing IDictionary with instance properties as a POCO for OpenAPI schema generation with Swashbuckle?如何将使用实例属性实现 IDictionary 的对象视为使用 Swashbuckle 生成 OpenAPI 模式的 POCO?
【发布时间】:2023-02-03 09:56:14
【问题描述】:

我正在尝试使用 Swashbuckle.AspNetCore NuGet 为 ASP.NET Core 6 最小 Web API 生成 OpenAPI 3 (OAS3) 文档。文档和模式生成一切就绪;但是,我有一个用于表示系统中实体的基本类型和许多为业务逻辑定义额外的特定于实体的属性的继承者。由于超出讨论范围的原因,这个基本实体类实现了IDictionary<,>,并且不可能删除这个接口。

因此,问题是:据我了解在 Swashbuckle 中生成 OAS3 模式期间数据契约解析器的源代码,实现 C# Dictionary 类型的类型将使用忽略实例属性的 Dictionary 契约解析器,从而生成一个被丢弃的空对象模式.我想覆盖此行为,以便在架构中正确记录实体属性。

到目前为止,我找到的唯一解决方案是从基础实体类中删除 IDictionary<,> 接口,之后模式生成成功并且所有实例属性都记录在文档模式桶中,但这有一个不幸的副作用,几乎破坏了所有OAS3 文档生成之外的系统区域是不可行的。

我一直在寻找一种方法来通知数据契约解析器关于实体类型使用哪个解析器,但是由于契约解析器在 Swashbuckle 中,我将不得不用我在 DI 中替换的完全自定义的解析器替换它们的版本容器。

【问题讨论】:

  • 只是一个疯狂的猜测:如果你在字典属性上放置一个 JSON ignore 属性,会发生什么?解析器是否会考虑到这一点?或者在您的常规序列化程序中产生这个新问题?
  • @Oliver 正常的 JSON(反)序列化方案今天工作正常。该对象本身实现了IDictionary(即class EntityClass : IDictionary<string, object>),因此不可能“忽略”该接口继承。

标签: c# swashbuckle datacontract swashbuckle.aspnetcore


【解决方案1】:

最简单的解决方案最终是根据 Swashbuckle NuGet 提供的版本实现我自己的 ISerializerDataContractResolver 版本,并在 DI 容器中替换它。跟随复制我的解决方案:

实施ISerializerDataContractResolver。您可以找到带有 on GitHub here 的 Swashbuckle 版本。如果您使用的是 Newtonsoft 而不是 System.Text.Json,则需要从同一 Github 存储库中的 Newtonsoft 版本构建。您需要自定义的主要部分是方法DataContract GetDataContractForType(Type)。您需要使用 if 检查来包装对 IsSupportedDictionary(...) 和 IsSupportedCollection(...) 的调用,以匹配您希望视为常规 object 的字典继承类型。这就是我的用例所需的全部内容。你的可能更复杂,需要更多的修改。

后调用builder.Services.AddSwaggerGen(...),交换你的实现:

// using Microsoft.Extensions.DependencyInjection.Extensions;
builder.Services.Replace(ServiceDescriptor.Transient(
    YourSerializerDataContractResolver.Factory));

我在我的实现中创建了一个静态工厂方法,同样基于 Swashbuckle 提供的实现:

// using Microsoft.AspNetCore.Mvc;
// using Microsoft.Extensions.Options;
// using System.Text.Json;
        public static ISerializerDataContractResolver Factory(IServiceProvider services)
        {
#if !NETSTANDARD2_0
            JsonSerializerOptions serializerOptions = services.GetService<IOptions<JsonOptions>>()?.Value?.JsonSerializerOptions
                ?? new JsonSerializerOptions();
#else
            JsonSerializerOptions serializerOptions = new JsonSerializerOptions();
#endif

            return new YourJsonSerializerDataContractResolver(serializerOptions);
        }

此工厂方法不是必需的,但由于它将实现工厂代码移到了单独的文件中,因此使应用程序启动更加简洁。

【讨论】:

    猜你喜欢
    • 2021-07-03
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多