CodeGym /课程 /C# SELF /验证 JSON

验证 JSONJSON Schema

C# SELF
第 47 级 , 课程 4
可用

1. 介绍

所以,你已经会把对象转成 JSON(和反过来)。但如果你的程序收到一些……奇怪的东西该怎么办?比如,你期望这样一个 JSON:

{
  "id": 123,
  "name": "Alice",
  "email": "alice@example.com"
}

但收到的是:

{
  "name": 42,
  "id": "not a number"
}

是的,C# 的序列化/反序列化器会试着把这些内容反序列化,但通常会导致运行时错误、数据丢失,甚至业务崩溃。在把数据继续传递、存库或通过网络发送之前,先确认数据是有效的 —— 否则你的代码就像没装保险的杂技演员。

这就是为什么需要验证:自动检查 JSON 是否符合规则 —— 值的类型、字段的必需性、范围、结构等等。

2. 有哪些 JSON 验证方式?

在 C# 和 .NET 里主要有三种做法:

  • 自写验证逻辑:手动解析对象,写检查并在出错时抛异常。
  • 在模型上用验证属性:比如来自 System.ComponentModel.DataAnnotations[Required][Range][EmailAddress] 等。
  • JSON Schema 验证 — 今天的主角!

JSON Schema 是一个标准,用来形式化描述一个合法文档应该长什么样。Schema 本身也是 JSON。你可以指定哪些字段需要、字段类型、允许的值范围等。

通过 schema 你可以描述:

  • 哪些字段必须存在。
  • 期待的类型(string、array、number、object……)。
  • 哪些字段是必需的,哪些不是。
  • 数值范围(比如年龄从 0150)。
  • 模式、长度、枚举等。

最简单的 schema 示例

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id":    { "type": "integer" },
    "name":  { "type": "string" }
  },
  "required": ["id", "name"]
}

3. JSON Schema 的主要元素

我们通过例子看看 JSON Schema 里常见的关键字都是什么意思。

关键字 说明 示例
$schema
指向 JSON Schema 标准的版本
"https://json-schema.org/draft/2020-12/schema"
type
值的类型(object, array, string, number 等)
"type": "object"
properties
对象属性的描述
"properties": { ... }
required
必需字段的数组
"required": ["id"]
items
数组元素的类型描述
"items": { ... }
enum
允许的值的枚举
"enum": ["A", "B"]
minimum
,
maximum
数字的限制
"minimum": 0
minLength
,
maxLength
字符串长度限制
"minLength": 3
pattern
字符串的正则表达式
"pattern": "^[a-zA-Z]+$"

可视化:一个表示人数组的 schema 示例

{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id":    { "type": "integer" },
      "name":  { "type": "string", "minLength": 2, "maxLength": 50 },
      "email": { "type": "string", "format": "email" }
    },
    "required": ["id", "name"]
  }
}

4. 在 C# 中如何把 JSON 跟 schema 校验

在 .NET 里没有内置的 JSON Schema 标准支持(截至 .NET 9)。实际项目通常用第三方库: NJsonSchemaNewtonsoft.Json.Schema (Json.NET Schema)。

安装 Newtonsoft.Json.Schema 包 (Json.NET Schema)

在终端(项目文件夹)里执行:

dotnet add package Newtonsoft.Json.Schema

重要: Newtonsoft.Json.Schema 是商业库(非商业用途免费)。对 pet 项目很合适。

用例:检查 JSON 是否匹配 schema

using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;

string schemaJson = @"{
  'type': 'object',
  'properties': {
    'id':    { 'type': 'integer' },
    'name':  { 'type': 'string' },
    'email': { 'type': 'string', 'format': 'email' }
  },
  'required': ['id', 'name']
}";

// 假设我们有这样的 JSON
string json = @"{
  'id': 123,
  'name': 'Alice',
  'email': 'alice@example.com'
}";

// 先解析 schema
JSchema schema = JSchema.Parse(schemaJson);

// 把 JSON 解析成 JToken
JToken jsonObj = JToken.Parse(json);

// 检查 JSON 是否符合 schema
bool valid = jsonObj.IsValid(schema, out IList<string> errors);

if (valid)
{
    Console.WriteLine("JSON 有效!");
}
else
{
    Console.WriteLine("JSON 无效!");
    foreach (var error in errors)
        Console.WriteLine(error);
}

如何在应用里使用验证?

通常流程:先验证(用 IsValid),再反序列化(用 JsonConvert.DeserializeObject<T>),然后才执行业务逻辑。这样可以在早期过滤掉脏数据。

if (jsonObj.IsValid(schema))
{
    // 一切正常,可以反序列化
    var person = JsonConvert.DeserializeObject<Person>(json);
}
else
{
    // 停止处理!数据不合法。
}

5. JSON Schema 在真实场景下的应用

什么时候需要验证?

  • 接收来自 API 的数据时(尤其是来自外部系统和不同客户端时)。
  • 在微服务或数据库之间迁移数据时。
  • 基于 schema 动态生成 UI 表单并自动填充时。
  • 面试题:经常会被问到“如果收到了错误的 JSON 怎么办?”

给好奇者的有趣点

  • 格式检查:"format""email""date-time"
  • 组合规则:anyOfoneOfallOf
  • 嵌套对象和数组的验证。
  • 根据需要扩展 schema。

6. 一个较大的实战示例

输入数据(用户列表):

[
  { "id": 1, "name": "Alice", "email": "alice@example.com" },
  { "id": 2, "name": "Bob" },
  { "id": "chto eto?", "name": 123, "email": "not-an-email" }
]

Schema:

{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id":    { "type": "integer" },
      "name":  { "type": "string", "minLength": 2, "maxLength": 50 },
      "email": { "type": "string", "format": "email" }
    },
    "required": ["id", "name"]
  }
}

在 .NET 里检查:

string jsonArray = @"[ ... ]"; // 见上面
string schemaJson = @"{ ... }"; // 见上面

JSchema schema = JSchema.Parse(schemaJson);
JToken arrayToken = JToken.Parse(jsonArray);

bool isValid = arrayToken.IsValid(schema, out IList<string> errs);
if (!isValid)
{
    foreach (var error in errs)
        Console.WriteLine(error);
    // 可能的错误示例:
    // "String 'chto eto?' is not a valid integer."
    // "Integer 123 is not a valid string."
    // "String 'not-an-email' is not a valid email address."
}

7. 使用 JSON Schema 时常见错误

错误 #1:schema 和实际数据不同步。 修改模型后忘记更新 schema。验证要么放行错误,要么拒绝正确的数据。

错误 #2:schema 类型和模型类型不匹配。 模型里的字段类型换了(比如 id 变成了字符串),而 schema 还写着 integer —— 验证会报错。

错误 #3:缺少对业务关键字段的必需性声明。 字段可能没被标记为必需,但业务逻辑依赖它,缺失会导致故障。

错误 #4:数据格式不正确。 字符串看起来像 email 或日期,但可能不合法。使用 format 或额外检查。

错误 #5:所用库滞后于标准。 标准在发展,库不一定跟得上。有些检查可能缺失或行为不同。

1
调查/小测验
处理JSON数据第 47 级,课程 4
不可用
处理JSON数据
JSON语法和结构基础
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION