#c# #asp.net-mvc #openapi
#c# #asp.net-mvc #openapi
Вопрос:
У нас есть API, определенный спецификацией OpenAPI (v3). Существует класс Animal, от которого наследуют Cat и Dog. Когда сгенерированный клиент C # выполняет запрос, скажем, для List<Animal>
, они правильно десериализуются как дочерние классы. Однако, если мы попытаемся ОПУБЛИКОВАТЬ List<Animal>
, содержащий Cats и Dogs, сгенерированный C # ASP.NET серверная часть получает их только как Animals вместо дочерних классов. Когда мы отправляем Cat с помощью Postman, серверная часть получает 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 теряет свои дочерние свойства.
Как мы можем настроить определение или генерацию, чтобы эти классы были должным образом десериализованы на стороне сервера?
Комментарии:
1. Опубликуйте свой код — классы, клиентский код, который создает этот post, действие MVC, которое получает post.
Ответ №1:
Это оказалось очень простым решением. Генерация кода на стороне клиента включала 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
, чтобы получить пакет.