Почему обязательные поля не учитываются в моей схеме JSON?

Я пытаюсь шаг за шагом научиться проверке схемы 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 с пустым именем, для заполнения обязательного поля?

ПРИМЕЧАНИЕ. Эти действительные/недействительные результаты точно такие же, как и при удалении «обязательного» элемента из схемы. Вот почему я вообще создал этот вопрос; Я не уверен, что использую его неправильно.

Спасибо.

Для справки, «требуется» в вашей схеме JSON просто означает «свойство присутствует». Никакого отношения к стоимости недвижимости это не имеет.

gunr2171 08.08.2024 20:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Что касается вашей линии

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
};

Это правило не выполняется с ошибкой:

Неверный тип. Ожидалась строка, но получено значение Null.

для FirstName

Это можно было бы легко исследовать, если бы вы использовали эту перегрузку метода:

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

который показывает, что не так:

По поводу другой линии

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"
}

это не пройдет проверку.

Спасибо большое, Михал. Это охватывает почти все, что мне нужно.

Felix Cartwright 08.08.2024 20:33

Это неправильное поведение схемы JSON.

Вы пытаетесь проверить noFNamePerson

JObject noFNameObj = JObject.Parse(JsonConvert.SerializeObject(noFNamePerson)); Что определяется, как показано ниже

// Я ожидаю, что это будет правильно, поскольку есть LName и возраст. Человек noFNamePerson = новый Человек() { Фамилия = "Кассир", Возраст = 30 }; Это правило не выполняется с ошибкой:

Неверный тип. Ожидалась строка, но получено значение Null.

для имени


В вашей схеме написано required: [LastName, Age]

Если вы не пройдете FirstName, это все еще действующий экземпляр. JSON Schema — это язык, основанный на ограничениях, что означает, что проверяются только ПРИМЕНЕННЫЕ ограничения. Все остальное игнорируется

Единственное ограничение, которое вы применили к FirstName, — это type: string, IF и ONLY IF, если это свойство определено в экземпляре.

properties: 
  FirstName:
    type: string

Похоже, ваш json неправильно сериализует все свойства и создает экземпляр FirstName как нулевой.

Вы можете попробовать использовать аннотации, чтобы сообщить сериализатору желаемое поведение.

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; }
   }

Другие вопросы по теме