首页 > 解决方案 > 如何将请求主体反序列化为子类?

问题描述

我们有一个由 OpenAPI 规范 (v3) 定义的 API。有一个 Cat 和 Dog 都继承自的 Animal 类。当生成的 C# 客户端发出请求时,例如对 a List<Animal>,它们被正确地反序列化为子类。但是,如果我们尝试发布List<Animal>包含 Cats 和 Dogs 的内容,生成的 C# ASP.NET 后端只会将它们作为 Animals 而不是子类获取。当我们使用 Postman 发布 Cat 时,后端会收到 Animal,所以我很确定这是 ASP.NET 生成问题。

spec.yaml 是:

openapi: 3.0.0
paths:
  /saveData:
    post:
      description: Send all the data required
      parameters:
        - name: id
          in: query
          required: true
          description: The id of the animal
          schema:
            type: string
            format: uuid
            example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SaveData'
      responses:
        200:
          description: The animal
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Animal'
        401:
          $ref: '#/components/responses/Unauthorised'
        400:
          $ref: '#/components/responses/BadRequest'

components:
  schemas:
    SaveData:
      type: object
      required:
        - animals
      properties:
        animals:
          type: array
          description: A list of animals
          items:
            $ref: '#/components/schemas/Animal'

    Animal:
      type: object
      discriminator:
        propertyName: className
      required:
        - "id"
        - "name"
        - "className"
      properties:
        id:
          type: string
          description: The unique ID of this object
          format: uuid
          example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        name:
          type: string
          description: Gives a name to the animal
          example: Bob
        className:
          type: string
          description: Determines which child class this object is
          example: Cat

    Cat:
      allOf:
        - $ref: '#/components/schemas/Animal'

    Dog:
      allOf:
        - $ref: '#/components/schemas/Animal'
        - type: object
          required:
            - "breed"
          properties:
            breed:
              type: string
              description: The breed of dog
              example: Terrier
              nullable: true

一个示例请求正文将是:

{
    "animals": [
        {
            "id": "84d40807-4c68-4b41-9c24-619847e80269",
            "name": "Bob",
            "className": "Cat"
        },
        {
            "id": "67a4b35e-4fc3-4a67-a77a-2a032640559f",
            "name": "Spot",
            "breed": "Husky",
            "className": "Dog"
        }
    ]
}

这些都被反序列化为 Animal,因此 Dog 失去了它的子属性。

我们如何调整定义或生成以允许这些类在服务器端正确反序列化?

标签: c#asp.net-mvcopenapi

解决方案


事实证明这是一个非常容易解决的问题。客户端代码生成包括JsonSubtypes正确反序列化所需的属性。

在上面的示例中,Animal 类的开头应如下所示:

using JsonSubTypes;

[JsonConverter(typeof(JsonSubtypes), "className")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Cat")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Dog")]
public partial class Animal
{
    // Class stuff here
}

我也不得不跑去dotnet add .\myproject.csproj package JsonSubTypes拿包裹。


推荐阅读