I'm trying to modernize a .NET Framework WCF application into a .NET 9 OpenAPI application.
I have created an ASP.NET Core Web API project with default settings, targeting .NET 9.
This is what my Program.cs
looks like:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
In the default WeatherForecastController
, I've added this method:
[HttpGet("vehicle", Name = "GetVehicle")]
public RequestVehicle Vehicle([FromBody] RequestVehicle requestVehicle)
{
requestVehicle.Vehicle.Start();
return requestVehicle;
}
which uses these classes:
public class RequestVehicle
{
public Vehicle Vehicle { get; set; }
}
public abstract class Vehicle
{
public string Status { get; set; }
public string Name { get; set; }
public abstract void Start();
protected Vehicle()
{
Status = "Not running";
}
}
public class Car : Vehicle
{
public Car()
{
Name = "Car";
}
public override void Start()
{
Console.WriteLine("Broemmm pruttle put");
Status = "Running";
}
}
When I run the application and go to:
https://localhost:7262/openapi/v1.json
I get this JSON:
{
"openapi": "3.0.1",
"info": {
"title": "WebApplication3 | v1",
"version": "1.0.0"
},
"servers": [
{
"url": "https://localhost:7262"
},
{
"url": "http://localhost:5136"
}
],
"paths": {
"/WeatherForecast": {
"get": {
"tags": [
"WeatherForecast"
],
"operationId": "GetWeatherForecast",
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"text/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
}
}
}
}
}
},
"/WeatherForecast/vehicle": {
"get": {
"tags": [
"WeatherForecast"
],
"operationId": "GetVehicle",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"RequestVehicle": {
"type": "object",
"properties": {
"vehicle": {
"$ref": "#/components/schemas/Vehicle"
}
}
},
"Vehicle": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"WeatherForecast": {
"type": "object",
"properties": {
"date": {
"type": "string",
"format": "date"
},
"temperatureC": {
"type": "integer",
"format": "int32"
},
"temperatureF": {
"type": "integer",
"format": "int32"
},
"summary": {
"type": "string",
"nullable": true
}
}
}
}
},
"tags": [
{
"name": "WeatherForecast"
}
]
}
Using this JSON, I create the client with NSwagStudio.
Here is a part of the generated code:
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class RequestVehicle
{
[Newtonsoft.Json.JsonProperty("vehicle", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public Vehicle Vehicle { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class Vehicle
{
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Status { get; set; }
[Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
The issue is that the Car
object is missing from the generated code in NSwagStudio. I've tried several approaches with ChatGPT, but it seems that I need to explicitly tell the Vehicle object that it can also be a Car
.
I've tried multiple suggestions, but I can't get it to work.
I'm trying to modernize a .NET Framework WCF application into a .NET 9 OpenAPI application.
I have created an ASP.NET Core Web API project with default settings, targeting .NET 9.
This is what my Program.cs
looks like:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
In the default WeatherForecastController
, I've added this method:
[HttpGet("vehicle", Name = "GetVehicle")]
public RequestVehicle Vehicle([FromBody] RequestVehicle requestVehicle)
{
requestVehicle.Vehicle.Start();
return requestVehicle;
}
which uses these classes:
public class RequestVehicle
{
public Vehicle Vehicle { get; set; }
}
public abstract class Vehicle
{
public string Status { get; set; }
public string Name { get; set; }
public abstract void Start();
protected Vehicle()
{
Status = "Not running";
}
}
public class Car : Vehicle
{
public Car()
{
Name = "Car";
}
public override void Start()
{
Console.WriteLine("Broemmm pruttle put");
Status = "Running";
}
}
When I run the application and go to:
https://localhost:7262/openapi/v1.json
I get this JSON:
{
"openapi": "3.0.1",
"info": {
"title": "WebApplication3 | v1",
"version": "1.0.0"
},
"servers": [
{
"url": "https://localhost:7262"
},
{
"url": "http://localhost:5136"
}
],
"paths": {
"/WeatherForecast": {
"get": {
"tags": [
"WeatherForecast"
],
"operationId": "GetWeatherForecast",
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"text/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
}
}
}
}
}
},
"/WeatherForecast/vehicle": {
"get": {
"tags": [
"WeatherForecast"
],
"operationId": "GetVehicle",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/RequestVehicle"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"RequestVehicle": {
"type": "object",
"properties": {
"vehicle": {
"$ref": "#/components/schemas/Vehicle"
}
}
},
"Vehicle": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"WeatherForecast": {
"type": "object",
"properties": {
"date": {
"type": "string",
"format": "date"
},
"temperatureC": {
"type": "integer",
"format": "int32"
},
"temperatureF": {
"type": "integer",
"format": "int32"
},
"summary": {
"type": "string",
"nullable": true
}
}
}
}
},
"tags": [
{
"name": "WeatherForecast"
}
]
}
Using this JSON, I create the client with NSwagStudio.
Here is a part of the generated code:
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class RequestVehicle
{
[Newtonsoft.Json.JsonProperty("vehicle", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public Vehicle Vehicle { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class Vehicle
{
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Status { get; set; }
[Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
The issue is that the Car
object is missing from the generated code in NSwagStudio. I've tried several approaches with ChatGPT, but it seems that I need to explicitly tell the Vehicle object that it can also be a Car
.
I've tried multiple suggestions, but I can't get it to work.
Share Improve this question edited Mar 20 at 17:37 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Mar 20 at 15:28 1408786user1408786user 2,0142 gold badges23 silver badges43 bronze badges1 Answer
Reset to default 0One way to handle that is to use the System.Text.Json instrumentation for polymorphic serialization (docs). For example you can mark the base class with corresponding attribute:
[JsonDerivedType(typeof(Car), "car")]
public abstract class Vehicle
{
// ...
}
Which will result in the following OpenAPI spec:
"components": {
"schemas": {
"RequestVehicle": {
"type": "object",
"properties": {
"vehicle": {
"$ref": "#/components/schemas/Vehicle"
}
}
},
"Vehicle": {
"required": [
"$type"
],
"type": "object",
"anyOf": [
{
"$ref": "#/components/schemas/VehicleCar"
}
],
"discriminator": {
"propertyName": "$type",
"mapping": {
"car": "#/components/schemas/VehicleCar"
}
}
},
"VehicleCar": {
"properties": {
"$type": {
"enum": [
"car"
],
"type": "string"
},
"status": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
}
Which seems to be handled by NSwag based on the generated JsonInheritanceConverter
and etc.
Note that this approach will result in extra property added to JSON for the discriminator (i.e. the $type
one)
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744399551a4572317.html
评论列表(0条)