Net Core Web Api – 如何为 SwaggerDoc 映射Optional

2024-02-24

我在用着Optional<T>在我的 DTO 中实现 Json Patch (details https://stackoverflow.com/questions/71024060/distinguish-between-null-and-not-present-using-json-merge-patch-with-netcore-web/71074603#71074603)。类型 T 存储在Optional<T>班级。 Optional 类允许区分 null 和未提供。

public readonly struct Optional<T>
    {
        public Optional(T? value)
        {
            this.HasValue = true;
            this.Value = value;
        }

        public bool HasValue { get; }
        public T? Value { get; }
        public static implicit operator Optional<T>(T value) => new Optional<T>(value);
        public override string ToString() => this.HasValue ? (this.Value?.ToString() ?? "null") : "unspecified";
    }

我使用的第一个 DTO 仅包含原始类型,例如

public class PatchGroupDTO
    {
        public Optional<Guid?> SalesGroupId { get; init; }       
        public Optional<string?> Name { get; init; }
    }

Swagger UI 显示的示例是错误的,因为它显示属性“value”:

{
  "salesGroupId": {
    "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "name": {
    "value": "string"
  }
}

我们的解决方案是映射 Startup.cs 中的类型。

services.AddSwaggerGen(c =>
  {
   c.SwaggerDoc("v1", new OpenApiInfo { Title = "xxx.API", Version = "v1" });
   c.MapType<Optional<Guid?>>(() => new OpenApiSchema { Type = "string", Format = "uuid" });
   c.MapType<Optional<string?>>(() => new OpenApiSchema { Type = "string" });
   c.MapType<Optional<bool?>>(() => new OpenApiSchema { Type = "boolean" });
   c.MapType<Optional<int?>>(() => new OpenApiSchema { Type = "integer" });
})

该示例随后正确显示为:

{
  "salesGroupId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "name":"string"
}

在我最新的 DTO 中,我需要嵌套对象。简化的 DTO 如下所示:

public record UpdateCartDTO
{
   public Optional<AddressDTO?> InvoicingAddress { get; init; }
   public Optional<List<CommentDTO>?> Comments { get; init; }
   public Optional<List<string>?> ReservationCodes { get; init; }
};

该示例将再次错误地显示嵌套值属性:

{
  "invoicingAddress": {
    "value": {
      "type": "string",
      "receipient": "string",
      "deliveryInstructio": "string",
      "street": "string",
      "streetNumber": "string",
      "streetAffix": "string",
      "zip": "string",
      "city": "string",
      "state": "string",
      "isO3": "string"
    }
  },
"comments": {
    "value": [
      {
        "language": "string",
        "comment": "string"
      }
    ]
  },
  "reservationCodes": {
    "value": [
      "string"
    ]   
  }
}

List<string>可以映射为:

c.MapType<Optional<List<string>?>>(
 () => new OpenApiSchema { Type = "array", Items = new OpenApiSchema { Type="string" } });

我在映射嵌套对象时遇到问题。我试过:

c.MapType<Optional<AddressDTO?>>(() => new OpenApiSchema { Type = "object" });

但这只显示空括号{}。按照我理解 api 的方式,我需要手动定义 AddressDTO 的所有类型Item = new OpenApiSchema{...}. 有没有什么解决方案可以只引用AddressDTO?

为Optional中使用的每个T定义一个MapType通常很麻烦。有什么办法可以实现从Optional到T的通用映射吗?就像是:

c.MapType<Optional<T?>>(() => new OpenApiSchema { Object= "T"});

关键是使用对现有模式的引用,以避免必须使用以下命令完全重新定义对象OpenApiSchema.

您可以使用下面的代码来映​​射Optional<AddressDTO?> :

s.MapType <Optional<AddressDTO?>>(() =>
    new OpenApiSchema
    {
        Type = "object",
        Reference = new OpenApiReference()
        {
            Type = ReferenceType.Schema,
            Id = nameof(AddressDTO)
        },
        Nullable = true
    });

替代方案为Optional<List<AddressDTO>?> :

s.MapType<Optional<List<AddressDTO>?>>(() =>
    new OpenApiSchema { 
        Type = "array",
        Items = new OpenApiSchema { 
            Type = "object",
            Reference = new OpenApiReference() { 
                Type = ReferenceType.Schema,
                Id = nameof(AddressDTO)
            }
        }, 
        Nullable = true 
    });

它假设AddressDTO具有可以引用的现有架构。 就我而言,Optional<AddressDTO?>是对此对象及其架构的唯一引用AddressDTO不是自动生成的。

所以你可以使用以下DocumentFilter生成缺少的架构:

internal class AdditionalSchemasDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        context.SchemaGenerator.GenerateSchema(typeof(AddressDTO), context.SchemaRepository);
    }
}

然后你在 Swagger 配置中这样称呼它:

s.DocumentFilter<AdditionalSchemasDocumentFilter>();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Net Core Web Api – 如何为 SwaggerDoc 映射Optional 的相关文章

  • EventHandler 应该始终用于事件吗?

    我一直在愉快地使用自定义委托类型和通用编写事件Action委托类型 没有真正考虑我在做什么 我有一些很好的扩展助手Action and EventHandler这使我倾向于使用那些预定义的委托类型而不是我自己的委托类型 但除此之外 除了惯例
  • 使用 Xamarin.Forms 和 Zxing 生成 QR 码

    我在网上看到了很多关于这个的内容 旧帖子 但似乎没有什么对我有用 我正在尝试从字符串中生成二维码并将其显示在应用程序中 这就是我一开始的情况 qrCode new ZXingBarcodeImageView BarcodeFormat Ba
  • .pdbs 会减慢发布应用程序的速度吗?

    如果 dll 中包含 pdb 程序调试 文件 则行号将出现在引发的任何异常的堆栈跟踪中 这会影响应用程序的性能吗 这个问题与发布与调试 即优化 无关 这是关于拥有 pdb 文件的性能影响 每次抛出异常时都会读取 pdb 文件吗 加载程序集时
  • 为什么在 C++ 中声明枚举时使用 typedef?

    我已经很多年没有写过任何 C 了 现在我正试图重新开始 然后我遇到了这个并考虑放弃 typedef enum TokenType blah1 0x00000000 blah2 0X01000000 blah3 0X02000000 Toke
  • C++中的类要具备什么条件才能成为容器?

    我是 C 编程新手 偶然发现了这个术语containers举例如下vector deque map etc 一个企业的最低要求应该是什么class应该满足被称为container in C 我将从 范围 这个概念开始 Range 只有两个方
  • 在 Mac OS X 上安装 libxml2 时出现问题

    我正在尝试在我的 Mac 操作系统 10 6 4 上安装 libxml2 我实际上正在尝试在 Python 中运行 Scrapy 脚本 这需要我安装 Twisted Zope 现在还需要安装 libxml2 我已经下载了最新版本 2 7 7
  • 如何查明 .exe 是否正在 C++ 中运行?

    给定进程名称 例如 程序 exe C 标准库没有这样的支持 您需要一个操作系统 API 来执行此操作 如果这是 Windows 那么您将使用 CreateToolhelp32Snapshot 然后使用 Process32First 和 Pr
  • C# Winforms Designer 无法打开,因为它无法在同一程序集中找到类型

    我收到以下错误 找不到类型 My Special UserControl 请确保引用包含此类型的程序集 如果此类型是您的开发项目的一部分 请确保已使用当前平台或任何 CPU 的设置成功构建该项目 但没有任何意义的是My Special Us
  • 检测 TextBox 中的 Tab 键按下

    I am trying to detect the Tab key press in a TextBox I know that the Tab key does not trigger the KeyDown KeyUp or the K
  • 如何在新窗口中打开图像或pdf文件?

    我有一个 gridview 它包含文件名和文件路径 图像和 pdf 格式文件 其中我使用了模板字段 在该字段下放置了 1 个图像按钮 单击该图像按钮 即 查看 按钮 时 我想在新窗口中打开所选文件 这是我的代码 protected void
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 选择 asp.net CheckBoxList 中的所有项目

    ASP NET 和 C 我想要一个带有 全选 项目的复选框列表 当这个特定项目是 已选择 所有其他都将被选择 也 当选择被删除时 这个项目 也将来自所有人 其他物品 选中 取消选中 任何其他项目只会有一个 对特定项目的影响 无论选择状态如何
  • 使用 Unity 在 C# 中发送 http 请求

    如何使用 Unity 在 C 中发送 HTTP GET 和 POST 请求 我想要的是 在post请求中发送json数据 我使用Unity序列化器 所以不需要 新的 我只想在发布数据中传递一个字符串并且能够 将 ContentType 设置
  • 在 Qt 中播放通知(频率 x)声音 - 最简单的方法?

    Qt 5 1 或更高版本 我需要播放频率为 x 的通知声音 n 毫秒 如果我能像这样组合音调那就太好了 1000Hz 持续 2 秒 然后 3000Hz 持续 1 秒 最简单的方法是使用文件 WAV MP3 例如如此处所述 如何用Qt播放声音
  • 将日期时间显示为 MM/dd/yyyy HH:mm 格式 C#

    在数据库中 日期时间以 MM dd yyyy HH mm ss 格式存储 但是 我想以 MM dd yyyy HH mm 格式显示日期时间 我通过使用 String Format 进行了尝试 txtCampaignStartDate Tex
  • 不使用放置 new 返回的指针时的 C++ 严格别名

    这可能会导致未定义的行为吗 uint8 t storage 4 We assume storage is properly aligned here int32 t intPtr new void storage int32 t 4 I k
  • 使用 boost 异步发送和接收自定义数据包?

    我正在尝试使用 boost 异步发送和接收自定义数据包 根据我当前的实现 我有一些问题 tcpclient cpp include tcpclient h include
  • 对多个对象使用事件处理程序

    我有 20 件物品List
  • 在 C 中使用 #define 没有任何价值

    If a define没有任何价值地使用 例如 define COMMAND SPI 默认值是0吗 不 它的评估结果为零 从字面上看 该符号被替换为空 然而 一旦你有了 define FOO 预处理器条件 ifdef FOO现在将是真的 另
  • Emacs C++,打开相应的头文件

    我是 emacs 新手 我想知道 是否有在头文件 源文件和相应的源文件 头文件之间切换的快捷方式 是否有像通用 emacs 参考卡那样的参考卡 Thanks There s ff find other file 您可以使用以下方法将其绑定到

随机推荐