如何将请求正文反序列化为子类?

问题描述

我们有一个由OpenAPI规范(v3)定义的API。有一个动物类,猫和狗都继承自。当生成的C#客户端发出请求时,例如说List<Animal>,它们将正确反序列化为子类。但是,如果我们尝试发布包含猫和狗的List<Animal>,则生成的C#ASP.NET后端只会将它们作为动物而不是子类来获取。当我们使用邮递员发布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失去了它的子属性

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

解决方法

事实证明这是一个非常简单的修复。客户端代码生成包含正确反序列化所需的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来获取软件包。