RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.79k stars 1.29k forks source link

Class ininheritance bug #4506

Open cschuchardt88 opened 1 year ago

cschuchardt88 commented 1 year ago

I want my client classes to be generated as abstract like the server classes are. But they are not. How can i fix this problem. Plus the generated function on client picks the 1st class in the list of oneOf which is AndConditionModel.

Server Configuration

Classes

public abstract class WitnessConditionModel
{
    public abstract WitnessConditionType Type { get; }
}

public class AndConditionModel : WitnessConditionModel
{
    public WitnessConditionModel[] Expressions { get; set; }
    public override WitnessConditionType Type => WitnessConditionType.And;
}

public class OrConditionModel : WitnessConditionModel
{
    public WitnessConditionModel[] Expressions { get; set; }
    public override WitnessConditionType Type => WitnessConditionType.Or;
}

public class GroupConditionModel : WitnessConditionModel
{
    public string Group { get; set; }
    public override WitnessConditionType Type => WitnessConditionType.Group;
}

Controller

[HttpGet("test", Name = "test")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WitnessConditionModel))]
public IActionResult Test()
{
    return Ok(new AndConditionModel() { Expressions = new[] { new OrConditionModel() { Expressions = new[] { new GroupConditionModel() { Group = "HelloWorld" } } } } });
}

Configuration

options.UseOneOfForPolymorphism();
options.SelectSubTypesUsing(baseType =>
{
    if (baseType == typeof(WitnessConditionModel))
    {
        return new[]
        {
            typeof(AndConditionModel),
            typeof(OrConditionModel),
            typeof(GroupConditionModel),
        };
    }
    return Enumerable.Empty<Type>();
});

swagger.json

"/api/v1/node/test": {
      "get": {
        "tags": [
          "Node"
        ],
        "operationId": "test",
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorModel"
                }
              }
            }
          },
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AndConditionModel"
                    },
                    {
                      "$ref": "#/components/schemas/OrConditionModel"
                    },
                    {
                      "$ref": "#/components/schemas/GroupConditionModel"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
-------
"AndConditionModel": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/WitnessConditionModel"
          }
        ],
        "properties": {
          "expressions": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/AndConditionModel"
                },
                {
                  "$ref": "#/components/schemas/OrConditionModel"
                },
                {
                  "$ref": "#/components/schemas/GroupConditionModel"
                }
              ]
            },
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/WitnessConditionType"
          }
        },
        "additionalProperties": false
      },
----

Response

{
  "expressions": [
    {
      "expressions": [
        {
          "group": "HelloWorld",
          "type": "Group"
        }
      ],
      "type": "Or"
    }
  ],
  "type": "And"
}

Client

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class WitnessConditionModel
{
    [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public WitnessConditionType Type { get; set; }

}

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public enum WitnessConditionType
{

    [System.Runtime.Serialization.EnumMember(Value = @"Boolean")]
    Boolean = 0,

    [System.Runtime.Serialization.EnumMember(Value = @"Not")]
    Not = 1,

    [System.Runtime.Serialization.EnumMember(Value = @"And")]
    And = 2,

    [System.Runtime.Serialization.EnumMember(Value = @"Or")]
    Or = 3,

    [System.Runtime.Serialization.EnumMember(Value = @"ScriptHash")]
    ScriptHash = 4,

    [System.Runtime.Serialization.EnumMember(Value = @"Group")]
    Group = 5,

    [System.Runtime.Serialization.EnumMember(Value = @"CalledByEntry")]
    CalledByEntry = 6,

    [System.Runtime.Serialization.EnumMember(Value = @"CalledByContract")]
    CalledByContract = 7,

    [System.Runtime.Serialization.EnumMember(Value = @"CalledByGroup")]
    CalledByGroup = 8,

}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class AndConditionModel : WitnessConditionModel
{
    [Newtonsoft.Json.JsonProperty("expressions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<AndConditionModel> Expressions { get; set; }

    [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public WitnessConditionType Type { get; set; }

}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class OrConditionModel : WitnessConditionModel
{
    [Newtonsoft.Json.JsonProperty("expressions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.Generic.ICollection<AndConditionModel> Expressions { get; set; }

    [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public WitnessConditionType Type { get; set; }

}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class GroupConditionModel : WitnessConditionModel
{
    [Newtonsoft.Json.JsonProperty("group", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string Group { get; set; }

    [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public WitnessConditionType Type { get; set; }

}

function

public virtual System.Threading.Tasks.Task<AndConditionModel> TestAsync()
{
    return TestAsync(System.Threading.CancellationToken.None);
}
cschuchardt88 commented 1 year ago

Why is it using BooleanCondition as the base class, when it's clearly not the base class to be using?

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class WitnessRule
{
    [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public WitnessRuleAction Action { get; set; }

    [Newtonsoft.Json.JsonProperty("condition", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public BooleanCondition Condition { get; set; }

}

image