【问题标题】:Using Newtonsoft.Json.Schema is there a way to intercept the generation of the "definitions" name?使用 Newtonsoft.Json.Schema 有没有办法拦截“定义”名称的生成?
【发布时间】:2017-12-20 16:16:31
【问题描述】:

鉴于我有以下类型:

public class MyClass
{
    public MyGenericClass<bool> Gen { get; set; }
}

public class MyGenericClass<T>
{
    [Required]
    public T Prop { get; set; }
}

我像这样设置模式生成器

var generator = new JSchemaGenerator
{
     ContractResolver = new CamelCasePropertyNamesContractResolver(),
     SchemaIdGenerationHandling = SchemaIdGenerationHandling.None
};

generator.GenerationProviders.Add(
     new StringEnumGenerationProvider { CamelCaseText = true });

我得到以下架构

{
  "definitions": {
    "MyGenericClass<Boolean>": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "prop": {
          "type": "boolean"
        }
      },
      "required": [
        "prop"
      ]
    }
  },
  "type": "object",
  "properties": {
    "gen": {
      "$ref": "#/definitions/MyGenericClass<Boolean>"
    }
  },
  "required": [
    "gen"
  ]
}

这很好,只是我需要与之共享架构的服务不喜欢尖括号“”。

有没有办法拦截定义名称的创建,以便我可以去掉 ?请注意,其他 SchemaIdGenerationHandling 也不起作用。

有点像

public class GenericSchemaProvider : JSchemaGenerationProvider
{
    public override bool CanGenerateSchema(JSchemaTypeGenerationContext context)
    {

        return context.ObjectType.IsGenericType && !context.ObjectType.IsAssignableFrom(typeof(IEnumerable));
    }

    public override JSchema GetSchema(JSchemaTypeGenerationContext context)
    {
        return CanGenerateSchema(context) ? CreateSchemaWithCustomId(context, context.Required) : null;
    }

    private static JSchema CreateSchemaWithCustomId(JSchemaTypeGenerationContext context, Required required)
    {
        var schema = context.Generator.Generate(context.ObjectType, required != Required.Always);
        schema.Id = new Uri(TypeName(context.ObjectType), UriKind.Relative);
        return schema;
    }

    private static string TypeName(Type type, string acc = "")
    {
        var name = type.Name;
        var index = name.IndexOf('`');
        return index == -1 ? acc+name : TypeName(type.GetGenericArguments()[0],acc+name.Substring(0, index));
    }
}

几乎可以工作

{
  "definitions": {
    "MyGenericClassNullableDouble": {
      "$id": "MyGenericClassNullableDouble",
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "prop": {
          "type": "number"
        }
      },
      "required": [
        "prop"
      ]
    },
    "MyGenericClassDouble": {
      "$id": "MyGenericClassDouble",
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "prop": {
          "type": "number"
        }
      },
      "required": [
        "prop"
      ]
    },
    "MyGenericClassBoolean": {
      "$id": "MyGenericClassBoolean",
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "prop": {
          "type": "boolean"
        }
      },
      "required": [
        "prop"
      ]
    }
  },
  "type": "object",
  "properties": {
    "genBool": {
      "$ref": "MyGenericClassBoolean"
    },
    "genDouble": {
      "$ref": "MyGenericClassDouble"
    },
    "genNulableDouble": {
      "$ref": "MyGenericClassNullableDouble"
    }
  }
}

但是这些引用并不是对定义的正确引用。

【问题讨论】:

    标签: c# json.net jsonschema


    【解决方案1】:

    我相信你在正确的轨道上,我认为你只需要提供自己的JSchemaGenerationProvider 实现,而不是使用StringEnumGenerationProvider。类似creating a custom provider:

    public class FormatSchemaProvider : JSchemaGenerationProvider
    {
        public override JSchema GetSchema(JSchemaTypeGenerationContext context)
        {
            // customize the generated schema for these types to have a format
            if (context.ObjectType == typeof(MyGenericClass<bool>))
            {
                return CreateSchemaWithFormat(
                   context.ObjectType, context.Required, "MyGenericClass");
            }
            // use default schema generation for all other types
            return null;
        }
    
        private JSchema CreateSchemaWithFormat(Type type, Required required, string format)
        {
            JSchemaGenerator generator = new JSchemaGenerator();
            JSchema schema = generator.Generate(type, required != Required.Always);
            schema.Format = format;
            return schema;
        }
    }
    

    然后添加新生代提供者:

    JSchemaGenerator generator = new JSchemaGenerator();
    generator.GenerationProviders.Add(new FormatSchemaProvider());
    JSchema schema = generator.Generate(typeof(MyClass));
    

    【讨论】:

    • 这不会更改定义条目。它只是添加了一个“格式”“定义”:{“MyGenericClass”:{“type”:[“object”,“null”],“properties”:{“Prop”:{“type”:“boolean " } }, "required": [ "Prop" ], "format": "MyGenericClass" } }
    • 我需要将 "definitions": { "MyGenericClass" 变成 "definitions": { "MyGenericClassBoolean" 并且所有属性都引用相同的名称,即 "properties": { "gen": { "$ref": "#/definitions/MyGenericClass" } 应该变成 "properties": { "gen": { "$ref": "#/definitions/MyGenericClassBoolean" }
    • @Yoztastic - 你可能需要CustomConverter
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多