newtonsoft.json + jsonschema 验证需用 jobject.load() 加载 json 并调用 isvalid(),配合 jschema.parse() 解析 schema;须缓存线程安全的 jschema 实例,启用 path 获取 jsonpath 错误定位,避免反序列化绕过验证。

用 Newtonsoft.Json + JsonSchema 验证 JSON 文件结构
JSON Schema 验证在 C# 里不是 .NET 原生能力,得靠第三方库。目前最稳、文档最全、支持 Draft-04/06/07 的仍是 Newtonsoft.Json 生态里的 Newtonsoft.Json.Schema(注意:它已**停止维护**,但仍在大量生产项目中跑着;别用 NuGet 上标“preview”的新包,那是个半成品)。
常见错误是直接反序列化再手工比字段——这不算验证,只是“没崩”,漏掉类型错、必填项空、枚举越界等深层问题。
- 安装时只加
Newtonsoft.Json和Newtonsoft.Json.Schema两个包,别混System.Text.Json相关的验证逻辑,它们不兼容 - Schema 文件必须是合法 JSON,且顶层是对象(不能是数组),否则
JSchema.Parse()会抛ArgumentException - 验证前先用
JObject.Load()读文件,别用JsonConvert.DeserializeObject<t>()</t>,后者会跳过 schema 检查直接转强类型 - 示例片段:
JObject data = JObject.Load(File.OpenText("input.json")); JSchema schema = JSchema.Parse(File.ReadAllText("schema.json")); IList<ValidationError> errors = new List<ValidationError>(); bool valid = data.IsValid(schema, out errors); if (!valid) { foreach (var e in errors) Console.WriteLine(e.ToString()); }
XML 文件用 XmlSchemaSet + XmlReaderSettings 做结构校验
.NET 自带的 XML Schema(XSD)验证足够可靠,关键在设置 XmlReaderSettings 时别漏掉 ValidationType = ValidationType.Schema 和 Schemas.Add(),否则等于没开验证。
容易踩的坑是把 XSD 文件路径写错,或 XSD 里用了 xs:import 却没把被引用的 schema 一并 Add() 进去,这时会报 XmlSchemaException:“无法解析引用的命名空间”。
- 确保 XSD 文件编码为 UTF-8(无 BOM),否则
XmlSchema.Read()可能静默失败 - 如果 XML 有命名空间,XSD 中的
targetNamespace必须和 XML 的xmlns完全一致,字符大小写敏感 - 验证时用
XmlReader.Create(stream, settings)包一层,不要直接XDocument.Load(),后者不触发 schema 校验 - 示例关键行:
var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; settings.Schemas.Add("", "schema.xsd"); // 空字符串表示默认命名空间 settings.ValidationEventHandler += (s, e) => Console.WriteLine(e.Message); using var reader = XmlReader.Create("data.xml", settings);
别在运行时动态编译 Schema(尤其是 JSON)
Newtonsoft.Json.Schema 的 JSchema.Parse() 内部会做语法树构建和类型推导,对大 Schema(>50KB)或高频调用场景(如 API 网关层),每次 Parse 都是明显性能瓶颈。有人图省事写成单例缓存,结果发现并发下 JSchema 实例不是线程安全的,偶尔验证结果错乱。
- 正确做法:启动时一次性
Parse()并缓存JSchema实例,用ConcurrentDictionary<string jschema></string>按文件名或哈希索引 - XML 的
XmlSchemaSet是线程安全的,可以放心单例复用 - 如果 Schema 来自用户上传,务必加长度限制(如 max 256KB)和超时(
CancellationToken),防止恶意构造的嵌套 schema 导致栈溢出
验证失败时,错误信息够不够定位?
默认的 ValidationError(JSON)或 XmlSchemaValidationException(XML)只告诉你“哪一行错了”,但不说明“为什么错”。比如 "age": "abc" 在要求 integer 的字段上,JSON Schema 错误信息可能是 “Expected integer, got string”,但不会指出是 $.user.profile.age 这个路径。
要拿到完整 JSONPath 或 XPath,必须手动遍历验证错误集合,拼接上下文。XML 方便些,异常里自带 LineNumber 和 LinePosition;JSON 则得靠 ValidationError.Path 字段(需开启 JSchema.GenerationOptions = SchemaGenerationOptions.None 并确保原始 JSON 用 JObject 加载)。
- JSON 场景下,检查
errors.Select(e => e.Path)是否为空——为空说明是顶层语法错(比如多逗号),不是结构错 - XML 场景下,
ValidationEventArgs.Exception.LineNumber是字节流位置,不是文件行号;若 XML 有 DTD 或注释,实际行号可能偏移 - 别依赖错误消息做自动化修复(比如自动转类型),验证环节只负责报错,清洗逻辑放前面
验证逻辑本身不难写,难的是让错误可追溯、性能不掉队、边界情况不崩——尤其当 Schema 来自外部或随配置热更时,路径处理、缓存生命周期、命名空间对齐这些点,一个没卡准,就变成线上排查黑洞。










