You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Category属性筛选生成JSON Schema的实现(Newtonsoft JSON)

基于Newtonsoft JSON生成指定Category属性成员的JSON Schema

我们使用Newtonsoft JSON(C#,.NET Framework 4.5),希望仅为类中标记了指定Category属性的成员生成JSON Schema。例如下面的School类,我们只需要生成Category为"Student"的成员对应的Schema:

class School
{
    [Editable(false)]
    [DisplayName("Student")]
    [Category("Student")]
    public string StudentName { get; set; }

    [Editable(true)]
    [Range(0, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    [Category("Student")]
    public int Id { get; set; } = 10;

    [Editable(false)]
    [DisplayName("ParentName")]
    [Category("Student")]
    public string ParentName { get; set; }

    [JsonProperty("ParentPhone", Required = Required.Default)]
    [PhoneMask("999-999-9999",
        ErrorMessage = "{0} value does not match the mask {1}.")]
    [Category("Student")]
    public string Phone;

    [Editable(true)]
    [Category("Staff")]
    public string TeacherName { get; set; }

    [Editable(true)]
    [Range(0, 10000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    [DefaultValue(5000)]
    [Category("Staff")]
    public int Salary { get; set; }

    [ReadOnly(true)]
    [Category("Student")]
    public bool AvailingTransport { get; set; } = true;
}

我们尝试了以下代码,但未能生效:

abstract class SelectedAttributesSerializationProvider : JSchemaGenerationProvider
{
    public override JSchema GetSchema(JSchemaTypeGenerationContext context)
    {
        var type = context.ObjectType;
        JSchema schema = null;

        var generator = new JSchemaGenerator();
        PropertyInfo[] myMembers = type.GetProperties();
       
        var categoryAttributes = myMembers.Where(c => c.CustomAttributes.Any(p => p.AttributeType.Name == "CategoryAttribute"));

        foreach(PropertyInfo categoryAttribute in categoryAttributes)
        {
            foreach(CustomAttributeData customAttributeData in categoryAttribute.GetCustomAttributesData())
            {
                if(customAttributeData.AttributeType.Name == "CategoryAttribute")
                {
                    generator.GenerationProviders.Add(this);
                }
            }           
        }
       
        schema = generator.Generate(type);
        return ModifySchema(schema, context);
    }

    public abstract JSchema ModifySchema(JSchema schema, JSchemaTypeGenerationContext context);

}

解决方案

正确的做法是通过自定义契约解析器(IContractResolver)筛选出符合Category要求的成员,再让Schema生成器基于筛选后的契约生成Schema。

步骤1:实现自定义契约解析器

这个解析器会过滤掉不包含目标Category属性的成员:

public class CategoryFilteredContractResolver : DefaultContractResolver
{
    private readonly string _targetCategory;

    public CategoryFilteredContractResolver(string targetCategory)
    {
        _targetCategory = targetCategory;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var allProperties = base.CreateProperties(type, memberSerialization);
        
        // 仅保留带有指定Category属性的成员
        return allProperties.Where(property => 
        {
            // 获取成员的元数据(属性或字段)
            var memberInfo = type.GetMember(property.UnderlyingName).FirstOrDefault();
            if (memberInfo == null) return false;
            
            // 检查是否存在目标Category属性
            var categoryAttribute = memberInfo.GetCustomAttribute<CategoryAttribute>();
            return categoryAttribute != null && categoryAttribute.Category == _targetCategory;
        }).ToList();
    }
}

步骤2:使用解析器生成Schema

将自定义解析器绑定到JSchemaGenerator,然后生成目标类的Schema:

// 初始化Schema生成器
var schemaGenerator = new JSchemaGenerator();
// 设置自定义契约解析器,指定目标Category为"Student"
schemaGenerator.ContractResolver = new CategoryFilteredContractResolver("Student");

// 生成School类的Schema
JSchema studentSchema = schemaGenerator.Generate(typeof(School));
// 输出Schema内容
Console.WriteLine(studentSchema.ToString());

原代码失效原因

之前的实现存在两个核心问题:

  1. 在GetSchema方法内新建JSchemaGenerator并添加自身到生成器的GenerationProviders,会导致循环调用,逻辑混乱。
  2. 没有真正过滤掉不符合要求的成员,只是遍历了属性的特性,没有对Schema生成过程做实际的筛选控制。

内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:23:19