5

我正在运行一个 SharePoint 2013 本地服务器,我在该服务器上部署了一个简单的 WCF 服务作为场解决方案。该服务接受包含单个 MS Word 文档作为有效负载的简单 Http 发布请求,并返回这些转换为 PDF 的文件。匿名用户可以通过 Http 访问该服务。WordAutomationService 作为 SharePoint 服务器的管理用户帐户运行。

服务类创建 Microsoft.Office.Word.Server.Conversions.SyncConverter 的新实例,并将 SharePoint 正在运行的 WordAutomationService 的代理传递给构造函数(连同一些 ConversionJobSettings)。最后,它使用输入流(Word 文档)和输出流(将包含 WordAutomationService 生成的 PDF 文档的 Web 响应)调用 SyncConverter 上的 Convert 方法。

创建 SyncConverter 时,我没有设置 UserToken 属性,因为对服务的访问是由匿名用户进行的。根据这里的评论https://msdn.microsoft.com/en-us/library/microsoft.office.word.server.conversions.syncconverter.usertoken.aspx这似乎没问题:

此属性的默认值是一个空引用(在 Visual Basic 中为 Nothing),它是匿名的。

此设置适用于具有几页的小型 Word 文档并返回预期的 PDF 文件。但是,一旦 SharePoint 上 WordAutomationService 的执行时间超过某个时间阈值(大约 5 秒),服务就会失败,因为它永远不会返回(这会导致客户端读取超时)。根据日志,其原因似乎是一段时间后同步转换作业将工作移至后台进程:

同步流作业转换时间过长。不要再等了。稍后检查其状态

然后,它通过调用 ConversionServiceApplicationProxy.BatchGetSyncJobStatus 定期轮询此作业的状态。不幸的是,这个调用失败了,因为它在内部尝试创建一个新通道来与这个进程对话,并为此请求一个安全令牌。然而,SecurityTokenService 无法完成令牌请求并引发异常:

An unhandled exception has occurred. The security token request cannot be completed. System.InvalidOperationException: The security token request cannot be completed.    
at Microsoft.SharePoint.SPSecurityContext.SecurityTokenForServiceContext(Uri contextUri)     
at Microsoft.SharePoint.SPChannelFactoryOperations.InternalCreateChannelActingAsLoggedOnUser[TChannel](ChannelFactory`1 factory, EndpointAddress address, Uri via)     
at Microsoft.Office.ConversionServices.Service.ConfigChannelFactory`1.CreateChannel(EndpointAddress address)     
at Microsoft.Office.ConversionServices.Service.ConversionServiceApplicationProxy.GetChannel(Uri uri)     
at Microsoft.Office.ConversionServices.Service.ConversionServiceApplicationProxy.ExecuteOnChannel(Uri endpointAddress, Action`1 action)     
at Microsoft.Office.ConversionServices.Service.ConversionServiceApplicationProxy.BatchGetSyncJobStatus(ICollection`1 ucids, Uri endpointAddress)     
at Microsoft.Office.ConversionServices.Service.BatchGetStatusPollingThread.Run()     
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)     
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)     
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)     
at System.Threading.ThreadHelper.ThreadStart() StackTrace:  
at onetnative.dll: (sig=37460b31-4453-4365-92f5-3a11c267be48|2|onetnative.pdb, offset=28F56) at onetnative.dll: (offset=15735)   

我现在不知道如何摆脱令牌问题,以便系统可以创建必要的通道来轮询转换作业状态。非常感谢任何帮助。谢谢!

(我不能发布完整的日志,因为它注册为垃圾邮件)

4

2 回答 2

5
于 2017-02-06T00:43:57.567 回答
0

通常当共享点服务应用程序相互交互时,这些服务使用服务应用程序框架(SAF)通过 wcf 调用维护当前用户上下文。它允许这些服务使用SPContext.Current,在日志中保存调用之间的相关 id 等等。当此上下文丢失时,服务将无法相互通信。例如,如果我们有一个启动新线程但没有为新创建的线程上下文设置用户的代码,就会发生这种情况。

根据您的描述,您的服务是匿名的,并且没有使用 SAF 来维护用户上下文,而是使用了一些需要存在该上下文的服务

可能的解决方案是使用 SAF(简而言之,这是一个棘手的配置 WCF)而不是没有身份验证的普通 WCF 服务

编辑:

另一种可能的解决方案可能是包装您的代码,RunWithElevatedPrivileges以使您的服务将共享点与应用程序池标识连接起来

于 2017-02-06T00:08:45.637 回答