使用 Schema 验证无效的 json 数据不会因反序列化而失败

Posted

技术标签:

【中文标题】使用 Schema 验证无效的 json 数据不会因反序列化而失败【英文标题】:Validation of an invalid json data with Schema not failing with Deserialization 【发布时间】:2020-03-11 07:19:39 【问题描述】:

我正在解析以下 JSON:

"names":"organizationNames":["name":"apple"] 

进入 C# 代码中定义的架构,如下所示。

public class QueryJson


    #region Properties

    [JsonProperty("organization")]
    public HeOrganization Organization  get; set; 

    [JsonProperty("names")]
    public HeName Names  get; set; 

    [JsonProperty("emails")]
    public List<HeEmailAddress> Emails  get; set; 

    #endregion


    #region Linked Classes

    public class HeOrganization
    
        [JsonProperty("id")]
        public Guid? ID  get; set; 
    

    public class HeName
    
        [JsonProperty("organizationNames")]
        [Required(ErrorMessage = "Organization Name is Missing")]
        public List<HeOrganizationName> OrganizationName  get; set; 

        public class HeOrganizationName
        
            [JsonProperty("name")]
            [Required(ErrorMessage = "Name is Missing")]
            public string Name  get; set; 
        
    

    public class HeEmailAddress
    
        [JsonProperty("address")]
        [Required]
        [EmailAddress]
        public string Address  get; set; 

    

    #endregion


如果我要传递一个明显无效的 JSON:

"names":"organizationNames":["user":"apple"]

我期待 DeserializeObject() 失败或抛出错误,但它只是将“名称”分配给 null。

var myJson = JsonConvert.DeserializeObject<T>(jsonFilter);

其中 T 是类的实例。

关于如何执行此类验证的任何建议?

【问题讨论】:

你试过了吗:newtonsoft.com/jsonschema T是什么类型的?它必须是 QueryJson 类类型 例如:var myJson = JsonConvert.DeserializeObject(jsonFilter); 是JsonConvert.DeserializeObject(jsonFilter); Json.NET 不支持RequiredAttribute,它支持[JsonProperty(Required = Required.Always)]。见:Using Required and JsonRequired in ASP.NET Core Model Binding with JSON body。这是否回答了您的问题,或者您是否需要一种解决方法来使 Json.NET 尊重 [RequiredAttribute] 以进行独立序列化? 【参考方案1】:

您可以使用Newtonsoft.Json.Schema 来验证任何给定 Json 的架构。

例如,对于您定义的类结构,可以生成一个等效的 Schema

var generator = new JSchemaGenerator();
var schema = generator.Generate(typeof(QueryJson));

生成的Schema如下


  "definitions": 
    "HeEmailAddress": 
      "type": [
        "object",
        "null"
      ],
      "properties": 
        "address": 
          "type": "string",
          "format": "email"
        
      ,
      "required": [
        "address"
      ]
    ,
    "HeName": 
      "type": [
        "object",
        "null"
      ],
      "properties": 
        "organizationNames": 
          "type": "array",
          "items": 
            "$ref": "#/definitions/HeOrganizationName"
          
        
      ,
      "required": [
        "organizationNames"
      ]
    ,
    "HeOrganization": 
      "type": [
        "object",
        "null"
      ],
      "properties": 
        "id": 
          "type": [
            "string",
            "null"
          ]
        
      ,
      "required": [
        "id"
      ]
    ,
    "HeOrganizationName": 
      "type": [
        "object",
        "null"
      ],
      "properties": 
        "name": 
          "type": "string"
        
      ,
      "required": [
        "name"
      ]
    
  ,
  "type": "object",
  "properties": 
    "organization": 
      "$ref": "#/definitions/HeOrganization"
    ,
    "names": 
      "$ref": "#/definitions/HeName"
    ,
    "emails": 
      "type": [
        "array",
        "null"
      ],
      "items": 
        "$ref": "#/definitions/HeEmailAddress"
      
    
  ,
  "required": [
    "organization",
    "names",
    "emails"
  ]

您现在可以使用 Schema 来验证您的 json。例如,对于 OP 中提供的示例无效 json

var invalidJson = @"""names"":""organizationNames"":[""user"":""apple""]";
var jsonInstance = JObject.Parse(invalidJson);
bool valid = jsonInstance.IsValid(schema); // False

【讨论】:

这很有帮助,谢谢!但我有一个后续问题 - 为什么按要求生成属性组织、名称和电子邮件?如果我不希望它被要求怎么办? 这可能有用github.com/JamesNK/Newtonsoft.Json.Schema/issues/9

以上是关于使用 Schema 验证无效的 json 数据不会因反序列化而失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中验证 JSON Schema 模式?

Json Schema 快速入门

JSON解析器之json schema校验及代码实现

JSON Schema(模式)

Json Schema

web接口参数校验神器-json schema 快速入门