ASP.NET Core Web API w/Swagger -我如何从请求体反序列化“oneOf”类型?

ahy6op9u  于 2023-08-05  发布在  .NET
关注(0)|答案(1)|浏览(139)

我正在使用ASP.NET核心最小Web API dotnet6。
Swashbuckle允许我通过使用基类并创建子类来将端点的结构定义为oneOfbuilder.Services.AddSwaggerGen(c => c.UseOneOfForPolymorphism());
这些是我定义的类:

public abstract class Shape { }
public class Circle : Shape { public double Radius { get; set; } }
public class Square : Shape { public double Length { get; set; } }

字符串
就生成的swagger模式而言,这完全按照预期工作:

"/oneOfTest": {
      "post": {
           ...
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Circle"
                  },
                  {
                    "$ref": "#/components/schemas/Square"
                  }
                ]


但是当我调用这个方法时,我得到了一个异常,因为服务试图将数据反序列化为Shape,而不是它的一个子类:
System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'Shape'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.

如何让我的服务将传入的JSON反序列化为适当的子类而不是基类?

注意:对于这个简单的示例,我将整个主体设置为oneOf,但我希望反序列化解决方案也适用于更大对象的部分。

m528fe3b

m528fe3b1#

编辑:正如@KirkLarkin所指出的,.NET 7为这个问题添加了一个解决方案,描述为here。我的解决方案适用于.NET 6。
我可以定义一个自定义转换器,通过从JsonConverter<Shape>继承来处理特定类型(Shape)的反序列化。下面是我的实现:

public class ShapeConverter : JsonConverter<Shape>
{
    public override Shape? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var shapeObj = JsonSerializer.Deserialize<JsonObject>(ref reader, options)!;
        if (shapeObj.ContainsKey(nameof(Circle.Radius)))
        {
            return shapeObj.Deserialize<Circle>(options);
        }
        else if (shapeObj.ContainsKey(nameof(Square.Length)))
        {
            return shapeObj.Deserialize<Square>(options);
        }
        else throw new Exception("Discriminator could not be identified");
    }

    public override void Write(Utf8JsonWriter writer, Shape value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

字符串
(Note我首先将其反序列化为一个通用的JsonObject,然后使用特定的判别器来确定我要查看的子类。我使用内置的反序列化方法,而不是直接使用Utf8JsonReader。)
然后,我可以在WebApplicationBuilder中注册该转换器:

builder.Services.Configure<JsonOptions>(o =>
{
    o.SerializerOptions.Converters.Add(new ShapeConverter());
});


现在,当我的处理程序接收到请求时,示例将被反序列化为正确的子类。

相关问题