代码之家  ›  专栏  ›  技术社区  ›  Felix Cartwright

为什么在我的JSON模式中没有遵守必填字段?

  •  0
  • Felix Cartwright  · 技术社区  · 11 月前

    我正在为一个公司项目一步一步地自学JSON模式验证(用C#),我已经达到了学习字段要求的地步,但我看到的结果似乎不符合我的“必填字段”规范,我可以用手来弄清楚原因。

    这是我保存在一个名为“TestJsonSchema.txt”的文件中的模式。。。

    {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "$id": "https://example.com/product.schema.json",
        "title": "Person",
        "description": "Simple person for testing schema validation",
        "type": "object",
        "properties": {
            "FirstName": {
                "description": "The person's first name.",
                "type": "string"
            },
            "LastName": {
                "description": "The person's last name.",
                "type": "string"
            },
            "Age": {
                "description": "Age of the person in years.",
                "type": "integer",
                "exclusiveMinimum": 18
            }
        },
        "required": ["LastName", "Age"]
    }
    

    …这是测试程序。。。

    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using Newtonsoft.Json.Schema;
    
       public class Person
       {
           public string FirstName { get; set; }
           public string LastName { get; set; }
           public int Age { get; set; }
       }
    
       public class Program
       {
           public static void Main(string[] args)
           {
               string schemaFilePath = @"C:\testtest\TestJsonSchema.txt";
               JSchema schema = JSchema.Parse(File.ReadAllText(schemaFilePath));
    
               // Should be valid.
               Person fullPerson = new Person()
               {
                   FirstName = "John",
                   LastName = "Doe",
                   Age = 25
               };
    
               // I expect this to be valid as there's a LName and age.
               Person noFNamePerson = new Person()
               {
                   LastName = "Teller",
                   Age = 30
               };
    
               // I expect this to be invalid as there's no LName
               Person noLNamePerson = new Person()
               {
                   FirstName = "Madonna",
                   Age = 56
               };
    
               // I expect this to be valid as both teh LastName and Age are populated.
               Person BlankFNamePerson = new Person()
               {
                   FirstName = "",
                   LastName = "Mason",
                   Age = 49
               };
    
               // I honestly don't know whether this should or shouldn't be valid since
               // the required LastName is blank.
               // (My first time with these validity checks.  Hence all these test cases)
                Person BlankLNamePerson = new Person()
               {
                   FirstName = "Cher",
                   LastName = "",
                   Age = 120
               };
               
               JObject fullObj = JObject.Parse(JsonConvert.SerializeObject(fullPerson));
               JObject noFNameObj = JObject.Parse(JsonConvert.SerializeObject(noFNamePerson));
               JObject noLNameObj = JObject.Parse(JsonConvert.SerializeObject(noLNamePerson));
               JObject blankFNameObj = JObject.Parse(JsonConvert.SerializeObject(BlankFNamePerson));
               JObject blankLNameObj = JObject.Parse(JsonConvert.SerializeObject(BlankLNamePerson));
    
               bool fullValid = fullObj.IsValid(schema);               // Coming up true.  EXPECTED
               bool noFNameValid = noFNameObj.IsValid(schema);         // Coming up false.  !! WHY?? !!
               bool noLNameValid = noLNameObj.IsValid(schema);         // Coming up false.  EXPECTED
               bool blankFNameValid = blankFNameObj.IsValid(schema);   // Coming up true.  EXPECTED
               bool blankLNameValid = blankLNameObj.IsValid(schema);   // Coming up true.  NOT SURE IF CORRECT.
    
               // THESE ARE MY QUICK AND DIRTY WAYS OF FINDING OUT WHAT IS AND ISN'T VALID.
               Console.WriteLine("Full person is valid: " + fullValid);
               Console.WriteLine("No First Name person is valid: " + noFNameValid);
               Console.WriteLine("No Last Name person is valid: " + noLNameValid);
               Console.WriteLine("Blank First Name person is valid: " + blankFNameValid);
               Console.WriteLine("Blank Last Name person is valid: " + blankLNameValid);            
           }
       }
    

    为了严格审查,以下是无名字者和空白名字者的转换JSON。。。

    没有名字(出现无效)

    {"FirstName":null,"LastName":"Teller","Age":30}
    

    空白名字(即将生效)

    {"FirstName":"","LastName":"Mason","Age":49}
    

    所以,长话短说, 为什么没有名字的人即使有必填字段也无效?此外,空白字符串(如空白名字JSON)的存在是否足以满足必填字段?

    注: 这些有效/无效结果与我 去除 模式中的“必需”项。这就是为什么我首先提出了这个问题;我不确定我是否使用不当。

    谢谢。

    1 回复  |  直到 11 月前
        1
  •  1
  •   Michał Turczyn    11 月前

    关于你的线路

    bool noFNameValid = noFNameObj.IsValid(schema);         // Coming up false.  !! WHY?? !!
    

    您尝试验证 noFNamePerson

    JObject noFNameObj = JObject.Parse(JsonConvert.SerializeObject(noFNamePerson));
    

    定义如下

    // I expect this to be valid as there's a LName and age.
    Person noFNamePerson = new Person()
    {
        LastName = "Teller",
        Age = 30
    };
    

    此规则失败,出现错误:

    类型无效。预期为字符串,但结果为空。

    对于 FirstName

    如果您使用此方法重载,则可以很容易地对此进行调查:

    bool noFNameValid = noFNameObj.IsValid(schema, out IList<ValidationError> errors);
    

    这表明出了什么问题: enter image description here

    关于另一条线

    bool blankLNameValid = blankLNameObj.IsValid(schema);   // Coming up true.  NOT SURE IF CORRECT.
    

    这适用于定义如下的对象:

    // I honestly don't know whether this should or shouldn't be valid since
    // the required LastName is blank.
    // (My first time with these validity checks.  Hence all these test cases)
    Person BlankLNamePerson = new Person()
    {
        FirstName = "Cher",
        LastName = "",
        Age = 120
    };
    

    空值仍然是一个值,而不是它的缺失,这就是它传递的方式。如果您将JSON验证定义如下:

    "LastName": {
        "minLength": 1,
        "description": "The person's last name.",
        "type": "string"
    }
    

    它将无法通过验证。

        2
  •  0
  •   Jeremy Fiel    11 月前

    这不是正确的JSON模式行为。

    您尝试验证noFNamePerson

    J对象编号FNameObj= J对象。解析(JsonConvert.SerializeObject(noFNamePerson)); 定义如下

    //我希望这是有效的,因为有一个L名称和年龄。 人员noFNamePerson=新人员() { 姓氏=“出纳员”, 年龄=30 }; 此规则失败,出现错误:

    类型无效。预期为字符串,但结果为空。

    名字


    你的模式说 required: [LastName, Age]

    如果你不通过 FirstName ,这仍然是一个有效的实例。JSON Schema是一种基于约束的语言,这意味着只有应用的约束才会被验证。其他任何内容都被忽略

    您应用的唯一约束 名字 type: string ,如果且仅当此属性在实例中定义时。

    properties: 
      FirstName:
        type: string
    

    看起来你的json错误地序列化了所有属性并实例化了 名字 为null。

    您可以尝试使用注释来通知序列化器您实际想要的行为。

    public class Person
       {
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
           public string FirstName? { get; set; }
           [JsonProperty(Required = Required.Always)] = string.Empty;
           public string LastName { get; set; }
           [JsonProperty(Required = Required.Always)]
           public int Age { get; set; }
       }