Json.Net.Schema:如何生成仅需要[Required]属性的模式?

问题描述

我正在编写一个用于使用resume.json文件project)的工具,并正在创建一个Json Schema来验证用户输入。我正在尝试使用 Json.Net.Schema 使它自动化,但是输出始终使所有属性成为必需,无论这些属性具有[required]还是[Jsonrequired]属性。 / p>

模式生成代码

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

var schema = generator.Generate(typeof(Resume));
var sb = new StringBuilder();
schema.Writeto(new JsonTextWriter(
    new IndentedTextWriter(
        new StringWriter(sb),"  ")
    )
{
    Formatting = Formatting.Indented,IndentChar = ' ',Indentation = 2,QuoteName = true
},new JSchemaWriterSettings
{
    Version = SchemaVersion.Draft7
});

File.WriteallText("E:\\resume.schema",sb.ToString());

继续学习班(和孩子们)

public class Resume
{
    [required]
    public Basics Basics { get; set; }
    public Work[] Work { get; set; }
    public Volunteer[] Volunteer { get; set; }
    public Education[] Education { get; set; }
    public Award[] Awards { get; set; }
    public Publication[] Publications { get; set; }
    public Skill[] Skills { get; set; }
    public Language[] Languages { get; set; }
    public Interest[] Interests { get; set; }
    public Reference[] References { get; set; }
}

public class Award
{
    [required]
    public string Title { get; set; }
    public string Date { get; set; }
    public string Awarder { get; set; }
    public string Summary { get; set; }
}

public class Basics
{
    [required]
    public string Name { get; set; }
    public string Label { get; set; }
    public Uri Picture { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Website { get; set; }
    public string Summary { get; set; }
    public Location Location { get; set; }
    public Profile[] Profiles { get; set; }
}

public class Education
{
    [required]
    public string Institution { get; set; }
    public string Area { get; set; }
    public string StudyType { get; set; }
    public string StartDate { get; set; }
    public string EndDate { get; set; }
    public string Gpa { get; set; }
    public string[] Courses { get; set; }
}

public class Interest
{
    [required]
    public string Name { get; set; }
    public string[] Keywords { get; set; }
}

public class Language
{
    [required]
    public string language { get; set; }
    [required]
    public string Fluency { get; set; }
}

public class Location
{
    public string Address { get; set; }
    [required]
    public string PostalCode { get; set; }
    [required]
    public string City { get; set; }
    [required]
    public string CountryCode { get; set; }
    public string Region { get; set; }
}

public class Profile
{
    [required]
    public string Network { get; set; }
    [required]
    public string Username { get; set; }
    [required]
    public string Url { get; set; }
}

public class Publication
{
    [required]
    public string Name { get; set; }
    public string Publisher { get; set; }
    public string ReleaseDate { get; set; }
    public string Website { get; set; }
    public string Summary { get; set; }
}

public class Reference
{
    [required]
    public string Name { get; set; }
    public string reference { get; set; }
}

public class Skill
{
    [required]
    public string Name { get; set; }
    [required]
    public string Level { get; set; }
    public string[] Keywords { get; set; }
}

public class Volunteer
{
    [required]
    public string Organization { get; set; }
    [required]
    public string Position { get; set; }
    public string Website { get; set; }
    public string StartDate { get; set; }
    public string EndDate { get; set; }
    public string Summary { get; set; }
    public string[] Highlights { get; set; }
}

public class Work
{
    [required]
    public string Company { get; set; }
    [required]
    public string Position { get; set; }
    public string Website { get; set; }
    [required]
    public string StartDate { get; set; }
    public string EndDate { get; set; }
    public string Summary { get; set; }
    public string[] Highlights { get; set; }
}

电流输出

{
  "$schema": "http://json-schema.org/draft-07/schema#","$id": "Resume","deFinitions": {
    "Award": {
      "$id": "Award","type": [
        "object","null"
      ],"properties": {
        "title": {
          "type": "string"
        },"date": {
          "type": [
            "string","null"
          ]
        },"awarder": {
          "type": [
            "string","summary": {
          "type": [
            "string","null"
          ]
        }
      },"required": [
        "title","date","awarder","summary"
      ]
    },"Basics": {
      "$id": "Basics","type": "object","properties": {
        "name": {
          "type": "string"
        },"label": {
          "type": [
            "string","picture": {
          "type": [
            "string","null"
          ],"format": "uri"
        },"email": {
          "type": [
            "string","phone": {
          "type": [
            "string","website": {
          "type": [
            "string","location": {
          "$id": "Location","type": [
            "object","properties": {
            "address": {
              "type": [
                "string","null"
              ]
            },"postalCode": {
              "type": "string"
            },"city": {
              "type": "string"
            },"countryCode": {
              "type": "string"
            },"region": {
              "type": [
                "string","null"
              ]
            }
          },"required": [
            "address","postalCode","city","countryCode","region"
          ]
        },"profiles": {
          "$id": "Profile[]","type": [
            "array","items": {
            "$id": "Profile","type": [
              "object","null"
            ],"properties": {
              "network": {
                "type": "string"
              },"username": {
                "type": "string"
              },"url": {
                "type": "string"
              }
            },"required": [
              "network","username","url"
            ]
          }
        }
      },"required": [
        "name","label","picture","email","phone","website","summary","location","profiles"
      ]
    },"Education": {
      "$id": "Education","properties": {
        "institution": {
          "type": "string"
        },"area": {
          "type": [
            "string","studyType": {
          "type": [
            "string","startDate": {
          "type": [
            "string","endDate": {
          "type": [
            "string","gpa": {
          "type": [
            "string","courses": {
          "$id": "String[]","items": {
            "type": [
              "string","null"
            ]
          }
        }
      },"required": [
        "institution","area","studyType","startDate","endDate","gpa","courses"
      ]
    },"Interest": {
      "$id": "Interest","keywords": {
          "$id": "String[]","keywords"
      ]
    },"Language": {
      "$id": "Language","properties": {
        "language": {
          "type": "string"
        },"fluency": {
          "type": "string"
        }
      },"required": [
        "language","fluency"
      ]
    },"Location": {
      "$ref": "Location"
    },"Profile": {
      "$ref": "Profile"
    },"Publication": {
      "$id": "Publication","publisher": {
          "type": [
            "string","releaseDate": {
          "type": [
            "string","publisher","releaseDate","Reference": {
      "$id": "Reference","reference": {
          "type": [
            "string","reference"
      ]
    },"Skill": {
      "$id": "Skill","level": {
          "type": "string"
        },"level","Volunteer": {
      "$id": "Volunteer","properties": {
        "organization": {
          "type": "string"
        },"position": {
          "type": "string"
        },"highlights": {
          "$id": "String[]","required": [
        "organization","position","highlights"
      ]
    },"Work": {
      "$id": "Work","properties": {
        "company": {
          "type": "string"
        },"startDate": {
          "type": "string"
        },"required": [
        "company","highlights"
      ]
    }
  },"properties": {
    "basics": {
      "$ref": "Basics"
    },"work": {
      "$id": "Work[]","type": [
        "array","items": {
        "$ref": "Work"
      }
    },"volunteer": {
      "$id": "Volunteer[]","items": {
        "$ref": "Volunteer"
      }
    },"education": {
      "$id": "Education[]","items": {
        "$ref": "Education"
      }
    },"awards": {
      "$id": "Award[]","items": {
        "$ref": "Award"
      }
    },"publications": {
      "$id": "Publication[]","items": {
        "$ref": "Publication"
      }
    },"skills": {
      "$id": "Skill[]","items": {
        "$ref": "Skill"
      }
    },"languages": {
      "$id": "Language[]","items": {
        "$ref": "Language"
      }
    },"interests": {
      "$id": "Interest[]","items": {
        "$ref": "Interest"
      }
    },"references": {
      "$id": "Reference[]","items": {
        "$ref": "Reference"
      }
    }
  },"required": [
    "basics","work","volunteer","education","awards","publications","skills","languages","interests","references"
  ]
}

如何获取模式生成器以使用required属性

解决方法

JSchemaGenerator具有属性DefaultRequired

获取或设置架构的默认必需状态。

由于某种原因,此属性的默认值为Required.AllowNull,如source所示:

public JSchemaGenerator()
{
    _schemaReferenceHandling = SchemaReferenceHandling.Objects;
    _defaultRequired = Required.AllowNull;
}

如果将其更改为Required.Default,则只有那些明确标记为必需的属性,例如与[Required][JsonProperty(Required = Required.Always)]一起使用,将在架构中按要求列出:

var generator = new JSchemaGenerator
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),SchemaIdGenerationHandling = SchemaIdGenerationHandling.TypeName,DefaultRequired = Required.Default,};

DefaultRequired的默认值不是documented,但应该是。您可以通过Newtonsoft打开issue,要求对文档进行澄清。

演示小提琴here