C# 并发问题-Saxon 9.6 on.NET、XSLT和自定义XmlResolver和CollectionUriResolver

C# 并发问题-Saxon 9.6 on.NET、XSLT和自定义XmlResolver和CollectionUriResolver,c#,xml,multithreading,xslt,saxon,C#,Xml,Multithreading,Xslt,Saxon,我想验证我对Saxon的XSLT对象和并发性的理解 基本上,我需要自定义解析器来将特定于请求的数据返回到转换,目前,我正在为每个请求的每个转换创建新的解析器实例。我已经收到了一个请求在另一个请求中使用的数据的早期报告,这是一个重大问题 使用Saxon 9.6.0.6和.NET 4.6(C#),Windows 7/Server 2012 我的代码可以为许多并发请求执行许多不同的共享转换。Saxon编译的XSLT对于性能来说是必须的。目前,代码是多线程的(在适当的情况下使用TPL和异步),并且不使

我想验证我对Saxon的XSLT对象和并发性的理解

基本上,我需要自定义解析器来将特定于请求的数据返回到转换,目前,我正在为每个请求的每个转换创建新的解析器实例。我已经收到了一个请求在另一个请求中使用的数据的早期报告,这是一个重大问题


使用Saxon 9.6.0.6和.NET 4.6(C#),Windows 7/Server 2012

我的代码可以为许多并发请求执行许多不同的共享转换。Saxon编译的XSLT对于性能来说是必须的。目前,代码是多线程的(在适当的情况下使用TPL和异步),并且不使用锁定(如果可能的话,希望避免这种情况)

我偶尔有报告称,在转换的输出中,数据在请求之间被错误地“泄漏”(即,可能是并发问题)。我不确定这是否与自定义XmlResolver或自定义CollectionUriResolver的行为有关。我在等待更多的信息。我还无法重新创建该问题(仍在处理此问题,如果可以,将发布更新)

我们的转换同时使用fn:doc和fn:collection

代码在应用程序启动时预编译所有可能的转换。这些可执行文件是共享的

对于事务中的给定转换,我的代码通过编译的可执行文件的.Load()调用创建一个XSLTTTransformer对象。这似乎创建了一个查看9.6HE代码的新对象(这是我所期望的)

接下来,我的代码将创建自定义XmlResolver和CollectionUriResolver的新实例(尚未移动到CollectionFinder,但认为这可能以相同的方式运行),并使用相应的特定于请求的文档/值/等填充这些实例,以供转换使用

这两个解析器的生命周期只有一次XSLT执行——它们不会被重用

我们将解析器与XsltTransform对象相关联,这是我知道的唯一方法:

Saxon.Api.XsltTransformer transform = executable.Load();
transform.InitialContextNode = sourceData; 
transform.Implementation.getConfiguration().
    setCollectionURIResolver(collectionResolver);
transform.InputXmlResolver = inputResolver;
在Saxon代码中,输入解析器看起来是基于实例的,因此不是共享的(最终出现在控制器类中,如下所示,当通过Load()创建XsltTransformer时,它本身就是一个新实例)

但是,我担心配置数据可能会被共享,在配置对象上设置集合解析器时(CollectionFinder似乎是相同的),我们可能会遇到并发问题

实现我所追求的结果的正确方法是什么?对于我们的定制解析器来说,用特定于请求的行为进行响应?我可以在每个转换中使用一对实例,其中包含请求特定的数据,还是必须在请求之间共享解析程序(可能将请求ID注入转换以形成传递给解析程序的URI的一部分)

轻微更新 看起来,您可以直接在控制器(“实现”)上或在配置上设置CollectionURIResolver,这些对象在内存中明显不同:

transform.Implementation.setCollectionURIResolver(collectionResolverOne);        
transform.Implementation.getConfiguration().
    setCollectionURIResolver(collectionResolverTwo);
但是,在运行时,调用的是配置的解析器(在上面的例子中是collectionResolverTwo)。我不确定控制员的副本有什么用途

此外,配置数据似乎确实是共享的,因为如果我从同一个可执行文件创建第二个转换器,并将其集合解析器设置为配置级别,这将更新第一个转换器使用的解析器


所以-我想我已经发现了我的问题-我现在需要知道在我的场景中应该做什么,我需要集合解析器为每个请求唯一地解析集合(例如,一个请求在一个特定集合中可能有五个条目,另一个可能有两个).

我认为,在解释你的问题时,你基本上是自己解决了问题。Saxon中的配置对象(在API级别支撑处理器)是共享的,在任何初始化之后,强烈建议不要使用setURIResolver()等方法更改其状态,因为此类更改将以未定义的方式影响正在进行的工作

Saxon有API对象和具有一对一对应关系的内部对象,内部对象不是100%封装的,因为有些用户需要访问更私密的功能。在Java世界中,还有一些JAXP类在概念上类似,但仅限于XSLT1.0功能。信件是:

关于整个Saxon环境的共享信息:

API:处理器内部:配置JAXP:TransformerFactory

可重用的XSLT编译器,包含用于编译样式表的选项:

API:XsltCompiler内部:编译器信息JAXP:无等效文件

一个已编译的样式表,可以重复执行(并在多个线程中并发执行)

API:XsltExecutable内部:可执行/准备样式表JAXP:模板

单个转换,使用一个样式表转换一个源文档:

API:XsltTransformerInternal:ControllerJAXP:Transformer

Saxon中的某些配置选项仅在配置级别可用,例如,可用的排序规则URI集是在该级别定义的,并且不能在不同的转换之间变化


但是,URIResolver通常可以在XSLT变压器/控制器级别定义。它们也可以在处理器/配置上设置,但如果您想在整个过程中使用相同的配置,这只是默认设置。在您的情况下,您应该在控制器级别设置它们。

谢谢!我认为我在这里面临的问题是由于9.6.0.6没有按预期工作。Upg
transform.Implementation.setCollectionURIResolver(collectionResolverOne);        
transform.Implementation.getConfiguration().
    setCollectionURIResolver(collectionResolverTwo);