XmlSchemaSet 验证必须显式设置 XmlResolver 和 ValidationType.Schema。需用 XmlUrlResolver 解析本地 XSD 引用,Add 后检查 Count≥1;XmlReaderSettings 必须启用 ValidationType.Schema、DtdProcessing.Prohibit 并注册 ValidationEventHandler;ASP.NET Core 不支持自动 Schema 验证,需手动验证 XML 流。

XmlSchemaSet 验证前必须加载 XSD 并设置 XmlSchemaSet.XmlResolver
直接用 XmlSchemaSet 加载本地 XSD 文件却验证失败,大概率是没处理 xs:import 或 xs:include 引用——XmlSchemaSet 默认的 XmlResolver 为 null,遇到外部引用会静默跳过或抛 XmlSchemaException。必须显式赋值一个能解析本地路径的 XmlResolver,例如 new XmlUrlResolver(),并确保 XSD 路径可访问(推荐用 IWebHostEnvironment.WebRootPath 或 IHostEnvironment.ContentRootPath 拼接绝对路径)。
- 若 XSD 存于
wwwroot/schemas/invoice.xsd,构造XmlResolver时 baseUri 应设为该目录的完整路径 - 调用
schemaSet.Add()后检查schemaSet.Count是否 ≥1,避免因加载失败导致后续验证始终通过 - 不要依赖相对路径字符串直接传给
Add();Add(null, "invoice.xsd")在 ASP.NET Core 中几乎必然失败
验证 XML 流时必须用 XmlReaderSettings 绑定 XmlSchemaSet 并启用 ValidationType.Schema
仅把 XmlSchemaSet 塞进 XmlReaderSettings.Schemas 不够,还必须设置 settings.ValidationType = ValidationType.Schema,否则解析器完全忽略 Schema 规则。同时需注册 settings.ValidationEventHandler 捕获具体错误位置和消息,否则验证失败只抛泛型 XmlException,无法定位是元素缺失还是类型不匹配。
-
settings.DtdProcessing = DtdProcessing.Prohibit必须显式设置,防止上传恶意 DTD 引发 XXE - 验证大文件时,
XmlReader.Create(stream, settings)的stream必须支持Seek(如MemoryStream),否则会报NotSupportedException - 若上传的是
IFormFile,先读入MemoryStream再验证,别直接用file.OpenReadStream()—— 多数情况下该流不可回溯
var schemaSet = new XmlSchemaSet();
schemaSet.XmlResolver = new XmlUrlResolver
{
Credentials = CredentialCache.DefaultCredentials
};
var xsdPath = Path.Combine(env.ContentRootPath, "Schemas", "order.xsd");
schemaSet.Add(null, xsdPath);
var settings = new XmlReaderSettings
{
Schemas = schemaSet,
ValidationType = ValidationType.Schema,
DtdProcessing = DtdProcessing.Prohibit,
ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema |
XmlSchemaValidationFlags.ProcessSchemaLocation |
XmlSchemaValidationFlags.ReportValidationWarnings
};
settings.ValidationEventHandler += (sender, e) =>
{
// 记录 e.Severity、e.Message、e.Exception.LineNumber
};
using var stream = new MemoryStream();
await file.CopyToAsync(stream);
stream.Position = 0;
using var reader = XmlReader.Create(stream, settings);
while (reader.Read()) { / 触发验证 / }
ASP.NET Core 模型绑定不支持自动 XML Schema 验证
别指望 [FromBody] 绑定到 XElement 或自定义类时自动走 XmlSchemaSet。ASP.NET Core 的 XML 输入格式化器(XmlSerializerInputFormatter)只做反序列化,不执行 Schema 校验。必须在 Action 内手动解析并验证,或封装为 ActionFilter 在模型绑定后介入。
- 若用
XmlSerializer反序列化,它本身不校验 Schema;得先用XmlReader过一遍验证,再用同一份流反序列化(注意流位置重置) - 在
ValidateModelfilter 中无法访问原始 XML 字节,所以验证必须放在 action body 或自定义 model binder 中 - 不要在
Startup.ConfigureServices里全局替换XmlSerializerInputFormatter来加验证——它不暴露XmlReaderSettings配置点,强行修改易破坏默认行为
常见错误:验证通过但实际结构不符
现象是 XmlReader.Read() 不抛异常,但业务逻辑读取 reader.GetAttribute("id") 时为 null。原因往往是 XSD 中该属性声明为 use="optional",而验证器只检查语法合法性,不强制存在性。真正的约束要靠 xs:assert(XSD 1.1)或应用层二次校验。
- ASP.NET Core 默认使用的 .NET SDK 仅支持 XSD 1.0,
xs:assert会被忽略,别写 - 对必填字段,XSD 中必须用
use="required";对内容格式(如日期格式),用xs:pattern而非正则注释 - 验证后仍建议用
XDocument.Load(reader)构建 DOM,再用 LINQ to XML 抽取字段——比边读边验证更可控,也方便日志记录原始片段
XSD 加载和验证链路中,最容易被跳过的环节是 XmlResolver 设置和 ValidationType 开关,这两个漏掉,其余代码写得再全也白搭。










