C# XmlSchemaSet的架构验证错误/线程安全性?
下午好 XML模式验证片段在开发/q&a环境中运行良好,但在生产环境中会产生一些奇怪的验证结果。通常的怀疑是代码对于线程来说是不安全的,并且生产场景的额外负载正在清除错误 具体情况如下。考虑到正在验证的XML是:C# XmlSchemaSet的架构验证错误/线程安全性?,c#,thread-safety,C#,Thread Safety,下午好 XML模式验证片段在开发/q&a环境中运行良好,但在生产环境中会产生一些奇怪的验证结果。通常的怀疑是代码对于线程来说是不安全的,并且生产场景的额外负载正在清除错误 具体情况如下。考虑到正在验证的XML是: <mssql:spExecute type="ResultSet" xmlns:mssql="urn:namespace"> <mssql:actor>IPASS</mssql:actor> <mssql:connection&
<mssql:spExecute type="ResultSet" xmlns:mssql="urn:namespace">
<mssql:actor>IPASS</mssql:actor>
<mssql:connection>ConnectionString</mssql:connection>
<mssql:storedProcedure>dbo.RedFox</mssql:storedProcedure>
</mssql:spExecute>
IPASS
连接串
红狐狸
在一整天中,大约300次执行(超过200万次)会产生以下例外情况:
System.Xml.Schema.XmlSchemaValidationException
The 'http://www.w3.org/2000/xmlns/:mssql' attribute is not declared.
System.Xml.Schema.XmlSchemaValidationException
这个http://www.w3.org/2000/xmlns/:mssql'属性未声明。
模式验证器似乎在抱怨名称空间声明
代码结构如下:
- 存在XmlSchemaSet的静态实例李>
- XmlSchemaSet实例的初始化是以线程安全的方式进行的李>
- 每个工作线程使用相同的XmlSchemaSet李>
- 验证发生在XmlSerializer.Deserialize()调用期间,使用XmlReader,XmlReaderSettings使用ValidationType.Schema初始化
有没有想过是什么原因导致命名空间声明阻塞了验证?我也有同样的问题。XML验证似乎不是只读操作,本文指出: 在它周围加上一把锁为我解决了这个问题
XmlSchemaSet
的只读使用是线程安全的。
直到Microsoft提供明确允许共享同一已编译文件的实现
线程之间的模式表示,唯一安全的做法是不共享XmlSchemaSet
进行验证似乎是合乎逻辑的
多个XmlDocument
(或XmlReader
)实例。
这是一个非常合理的场景,所以我不明白为什么它没有明确的定义
允许并记录
(更新:很明显,这在中得到了明确的保证。
为什么在.NET中不是这样?)这可能在.NET 4.0中得到修复,但没有记录在案 我在生产web服务中遇到了相同的错误。该错误类似,在峰值活动期间是随机的:“未声明xxx元素”。然而,在我的例子中,我们只是使用循环读取命令验证XML,而不是序列化对象 该服务是在.NET3.5下构建/运行的,在开发环境中,我可以通过启动5个线程并同时进行服务调用来轻松复制此错误。大约每10个请求中就有1个发生错误 当我坐下来解决这个问题时,我做的第一件事就是将服务升级到.NET4.0。一旦我这样做了,我就不能再产生这个错误了。我增加了线程数并删除了服务限制-仍然没有错误
虽然当前的文档仍然表明XmlSchema实例操作不保证线程安全,但3.5和4.0之间似乎有一些框架更改,提高了XmlSchema上读取/验证类型操作的线程安全性。否。事实并非如此。再读一遍。文章说,验证只在
XmlSchemaSet
上使用只读操作,因此多个线程可以共享单个XmlSchemaSet
实例,而无需显式锁定。它指出a)XmlSchemaSet
构造不是线程安全的,b)您需要确保您提供的ValidationEventHandler
回调是线程安全的。两者都很明显。它没有说明为什么假定XmlSchemaSet
上的只读操作确实是线程安全的。文档中说“任何实例成员[包括属性读取--ts]都不能保证线程安全。”您能详细说明一下吗?只读的定义是什么?在.NET Framework中,“只读操作”是什么意思,是否有官方定义?如果一个操作是只读的,那么如何从外部查看一个类呢?请记住,任何类型的延迟求值都会导致一个操作,该操作在外部为只读时会更改对象的内部状态。对于使用前编译的XmlSchemaSet
,期望所有读取都是真正的只读是有意义的。问题是,文档并没有公开这么说,我不确定是否可以安全地缓存已编译的模式。还要注意,如果这不起作用,我可能会在启动时创建一个XmlSchema对象列表,并包装对它们的访问,以便每个线程只使用一个。我相信创建对象会带来一些成本,最好不要每次请求都创建一个。好信息!我还做了一个类似的测试,结果似乎表明运行100个并发线程,每次读取和验证一个XML文档,共享同一个XmlSchemaSet时都没有中断。然而,即使这样,我也不会相信它,直到MSDN明确表示它是线程安全的。拥有一个预编译的模式对象池,并为每个线程获取一个对象以供使用,并在完成后返回池,这似乎是一个好主意。文档中不再提到它了,我们应该了解它现在是线程安全的吗?