c# - OpenAPI parameters with inheritence - Stack Overflow

I'm trying to modernize a .NET Framework WCF application into a .NET 9 OpenAPI application.I have

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 badges
Add a comment  | 

1 Answer 1

Reset to default 0

One 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

相关推荐

  • c# - OpenAPI parameters with inheritence - Stack Overflow

    I'm trying to modernize a .NET Framework WCF application into a .NET 9 OpenAPI application.I have

    7天前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信