最近项目中遇到了这样的需求,需要对上传的Json进行验证,以确保Json数据的准确性。前后使用了两种方式来验证:

 

  (1)第一种方式的实现思想:根据Json数据的格式,严格定义相应的类结构,并在System.Runtime.Serialization命名空间下的DataContractAttribute、DataMemberAttribute对class和property进行标注,如果property是必须提供的,则在Property上添加[DataMember(IsRequired = true)]。

  然后使用Newtonsoft.Json程序集中的JsonConvert.DeserializeObject<T>()方法加需要验证的JsonContent反序列化一下,并用try...catch包含反序列化语句,如果转换成功,则表明JsonContent格式满足要求。如果转换不成功,则会抛出异常,有catch接住。

  

  

try
            {
                var obj = JsonConvert.DeserializeObject<SkuConfigEntity>(skuManifest, new JsonSerializerSettings()
                {
                    Formatting = Formatting.Indented,
                    NullValueHandling = NullValueHandling.Ignore,
                    MissingMemberHandling = MissingMemberHandling.Error
                });
            }
            catch(Exception e)
            {
                return false;
            }

  

这种方法是最初使用的方法,个人认为不完善,也不够完美,转换出错的情况加,exception中不能给出具体的出错原因。

 

  (2)第二种实现思想:Json Schema(Json 模式)。在前辈的指点下,我知道了Json Schema,

 JSON 模式是一种基于 JSON 格式定义 JSON 数据结构的规范。它被写在 IETF 草案下并于 2011 年到期。JSON 模式:

  • 描述现有数据格式。
  • 干净的人类和机器可读的文档。
  • 完整的结构验证,有利于自动化测试。
  • 完整的结构验证,可用于验证客户端提交的数据。

JSON 模式验证库

目前有好几个验证器可用于不同的编程语言。但是目前最完整和兼容 JSON 模式的验证器是 JSV。

语言

程序库

C

WJElement (LGPLv3)

Java

json-schema-validator (LGPLv3)

.NET

Json.NET (MIT)

ActionScript 3

Frigga (MIT)

Haskell

aeson-schema (MIT)

Python

Jsonschema

Ruby

autoparse (ASL 2.0); ruby-jsonschema (MIT)

PHP

php-json-schema (MIT). json-schema (Berkeley)

JavaScript

Orderly (BSD); JSV; json-schema; Matic (MIT); Dojo; Persevere (modified BSD or AFL 2.0); schema.js.

   

 

 

 

 

 

 

 

 

 

JSON 模式示例

下面是一个基本的 JSON 模式,其中涵盖了一个经典的产品目录说明:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Product",
    "description": "A product from Acme's catalog",
    "type": "object",
    "properties": {
        "id": {
            "description": "The unique identifier for a product",
            "type": "integer"
        },
        "name": {
            "description": "Name of the product",
            "type": "string"
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
        }
    },
    "required": ["id", "name", "price"]
}

我们来看一下可以用于这一模式中的各种重要关键字:

关键字

描述

$schema

$schema 关键字状态,表示这个模式与 v4 规范草案书写一致。

title

用它给我们的模式提供了标题。

description

关于模式的描述。

type

type 关键字在我们的 JSON 数据上定义了第一个约束:必须是一个 JSON 对象。

properties

定义各种键和他们的值类型,以及用于 JSON 文件中的最小值和最大值。

required

存放必要属性列表。

minimum

给值设置的约束条件,表示可以接受的最小值。

exclusiveMinimum

如果存在 "exclusiveMinimum" 并且具有布尔值 true,如果它严格意义上大于 "minimum" 的值则实例有效。

maximum

给值设置的约束条件,表示可以接受的最大值。

exclusiveMaximum

如果存在 "exclusiveMinimum" 并且具有布尔值 true,如果它严格意义上小于 "maximum" 的值则实例有效。

multipleOf

如果通过这个关键字的值分割实例的结果是一个数字则表示紧靠 "multipleOf" 的数字实例是有效的。

maxLength

字符串实例字符的最大长度数值。

minLength

字符串实例字符的最小长度数值。

pattern

如果正则表达式匹配实例成功则字符串实例被认为是有效的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上述的Json模式可以验证如下Json串。

[
    {
        "id": 2,
        "name": "An ice sculpture",
        "price": 12.50
    },
    {
        "id": 3,
        "name": "A blue mouse",
        "price": 25.50
    }
]

在.Net中,Json Schema 通过Newtonsoft.Json.Schema命名空间下的JsonSchema类可以实现。

每一个JsonSchema实例表示对一个Property的描述以及限制。

    JsonSchema class的几个关键属性:

Type

设置Property的类型

 

Required

设置Property是否为必须的

 

Properties

包含的所有下一级Property的JsonSchema,该属性是Dictionary<string,JsonSchema>类型,添加子项之前需初始化。

 

Items

包含的所有下一级的数组项的JsonSchema,该属性是IList<JsonSchema>类型,添加子项之前需要初始化。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用Newtonsoft.Json.Schema命名空间下的IsValid()扩展方法,可实现对Json串的验证,该方法是JToken的扩展方法。

 

    public static JsonSchema GetSkuJsonSchema()
    {

                JsonSchema rootSchema = new JsonSchema() { Title = "Sku.Json", Type = JsonSchemaType.Object };

rootSchema.Properties = new Dictionary<string, JsonSchema>();
            rootSchema.Properties.Add("name", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            rootSchema.Properties.Add("displayName", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            rootSchema.Properties.Add("apimInstance", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            rootSchema.Properties.Add("apiPath", new JsonSchema() { Type = JsonSchemaType.String, Required = true });

            JsonSchema skuSchema = new JsonSchema() { Title = "skus", Type = JsonSchemaType.Array, Required = true };
            skuSchema.Properties= new Dictionary<string, JsonSchema>();
            skuSchema.Properties.Add("name", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            skuSchema.Properties.Add("tier", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            skuSchema.Properties.Add("subscriptionSkuQuota", new JsonSchema() { Type = JsonSchemaType.Integer, Required = false });
            skuSchema.Properties.Add("skutype", new JsonSchema() { Type = JsonSchemaType.String, Required = false });
            skuSchema.Properties.Add("skuquota", new JsonSchema() { Type = JsonSchemaType.String, Required = false });
            skuSchema.Properties.Add("apimProductId", new JsonSchema() { Type = JsonSchemaType.String, Required = false });

            JsonSchema locationsSchema = new JsonSchema() { Title = "locations", Type = JsonSchemaType.Array, Required = true };
            locationsSchema.Properties= new Dictionary<string, JsonSchema>();
            locationsSchema.Properties.Add("location", new JsonSchema() { Type = JsonSchemaType.String, Required = true });
            locationsSchema.Properties.Add("apimProductId", new JsonSchema() { Type = JsonSchemaType.String, Required = false });
            skuSchema.Properties.Add("locations", locationsSchema);

            JsonSchema meterIdsSchema = new JsonSchema() { Title = "meterIds", Type = JsonSchemaType.Array, Required = true };
            meterIdsSchema.Items = new List<JsonSchema>();
            meterIdsSchema.Items.Add(new JsonSchema() { Type = JsonSchemaType.String, Required = false });
            skuSchema.Properties.Add("meterIds", meterIdsSchema);

            JsonSchema requiredFeaturesSchema = new JsonSchema() { Title = "requiredFeatures", Type = JsonSchemaType.Array, Required = true };
            requiredFeaturesSchema.Items = new List<JsonSchema>();
            requiredFeaturesSchema.Items.Add(new JsonSchema() { Type = JsonSchemaType.String, Required = false });
            skuSchema.Properties.Add("requiredFeatures", requiredFeaturesSchema);

            rootSchema.Properties.Add("skus", skuSchema);

            return rootSchema;
  }

  

JToken jtoken=JToken.Parse(jsonContent);

IList<string> errorList;

var result=jtoken.IsValid(schema, out errorList);

如果验证成功,则返回ture,如果验证失败,则返回false,并且errorList中会包含详细的错误信息。