簡體   English   中英

是否可以使用 Swashbuckle 為 oneof 屬性生成引用模式?

[英]Is it possible to generate referenced schema for oneof properties using Swashbuckle?

默認情況下, Swashbuckleoneof屬性(universeCategory)生成一個內聯模式,如下所示。

"Universe":{
  "type":"object",
  "properties":{
    "universeCategory":{
      "oneOf":[
        {
          "$ref":"#/components/schemas/FullUniverse"
        },
        {
          "$ref":"#/components/schemas/HalfUniverse"
        }
      ],
      "discriminator":{
        "propertyName":"source",
        "mapping":{
          "FullUniverse":"#/components/schemas/FullUniverse",
          "HalfUniverse":"#/components/schemas/HalfUniverse"
        }
      }
    }
  }
}

是否可以通過將一些配置傳遞給Swashbuckle來生成如下所示的引用模式?

"Universe":{
  "type":"object",
  "properties":{
    "universe":{
      "$ref":"#/components/schemas/UniverseCategory"
    }
  },
  "additionalProperties":false
},
"UniverseCategory":{
  "oneOf":[
    {
      "$ref":"#/components/schemas/HalfUniverse"
    },
    {
      "$ref":"#/components/schemas/FullUniverse"
    }
  ],
  "discriminator":{
    "propertyName":"source",
    "mapping":{
      "HalfUniverse":"#/components/schemas/HalfUniverse",
      "FullUniverse":"#/components/schemas/FullUniverse"
    }
  }
}

Open API 生成器等工具目前僅支持上述格式。 因此,任何為oneof屬性生成引用模式的解決方法都值得贊賞。

我們可以添加一個自定義過濾器來將 oneof 模式的生成作為單獨的模式來處理,並且可以添加對生成的新模式的引用。

public class HandleOneOfPropertiesFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (schema?.Properties == null || context.Type == null)
        {
            return;
        }
        
        var propertiesWithOneOfHandling = context.Type.GetProperties()
            .Where(t => t.GetCustomAttributes().Any(c => c.GetType() == typeof(HandleOneOfPropertiesAttribute)));

        foreach (var selectedProps in propertiesWithOneOfHandling)
        {

            foreach (var props in schema.Properties)
            {
                if (selectedProps.Name.Equals(props.Key, StringComparison.InvariantCultureIgnoreCase))
                {
                    var oneOfProperty = (HandleOneOfPropertiesAttribute)context.Type.GetProperty(selectedProps.Name)
                        .GetCustomAttribute(typeof(HandleOneOfPropertiesAttribute));
                    
                    var name = oneOfProperty.Prefix + selectedProps.Name;

                    if (props.Value.Type == "array")
                    {
                        // Handling array type differently
                        context.SchemaRepository.Schemas.Add(name, props.Value.Items);
                        
                        var newSchema = new OpenApiSchema();
                        newSchema.Type = "array";
                        newSchema.Items  = new OpenApiSchema
                        {
                            Reference = new OpenApiReference
                            {
                                Id = name,
                                Type = ReferenceType.Schema
                            }
                        };
                        context.SchemaRepository.Schemas.Add(name + "Array", newSchema);
                        props.Value.Reference = new OpenApiReference
                        {
                            Id = name + "Array",
                            Type = ReferenceType.Schema
                        };
                    }
                    else
                    {
                        context.SchemaRepository.Schemas.Add(name, props.Value);    
                        props.Value.Reference = new OpenApiReference
                        {
                            Id = name,
                            Type = ReferenceType.Schema
                        };
                    }
                }
            }
        }
    }
}

然后我們需要定義一個屬性來確定我們需要在哪些屬性上處理生成,讓我們創建屬性

public class HandleOneOfPropertiesAttribute : Attribute
{
    public HandleOneOfPropertiesAttribute(string prefix)
    {
        Prefix = prefix;
    }
    
    public string Prefix { get; }
}

然后我們需要將此屬性用於 model 的 oneof 類型的屬性。 在下面的代碼片段中,我使用了“OneOfProp”前綴,因此生成的新模式將具有此前綴

public class ModelClass
{
   
    [HandleOneOfProperties("OneOfProp")]
    public Universe property1 { get; set; }


    [HandleOneOfProperties("OneOfProp")]
    public Galaxy property2 { get; set; }
}

最后在服務中注冊這個過濾器

services.AddSwaggerGen(c =>
 {
   c.SchemaFilter<HandleOneOfPropertiesFilter>();
 });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM