合并XML文档至SOAP信封时遇System.ArgumentException问题求助
问题描述
我们使用的API允许<Transaction>标签下包含多个<Message>及其他配置项。<Message>标签及其子节点是随任务变化的部分,因此将其独立存放在XmlDocument中,尝试合并回SOAP信封的<Transaction>节点时,调用AppendChild方法抛出异常:
System.ArgumentException: 'The node to be inserted is from a different document context.'
相关代码
生成SOAP信封的代码
public XmlDocument SoapRequestEnvelope() { XmlDocument envelope = new XmlDocument(); envelope.LoadXml(@"\n <?xml version=\"1.0\" encoding=\"utf-8\"?>\n <soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tyl=\"http://www.VendorWeb.com\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">\n <soap:Header>\n <wsa:To>https://test.VendorAccess.cloud/ExternalWebService/TranslationBridgeExternalService.asmx</wsa:To>\n <wsa:Action>http://www.MyVendor.com/VendorApiTxnExecutionSyncXml</wsa:Action>\n <wsse:Security soap:mustUnderstand=\"1\">\n <wsu:Timestamp wsu:Id =\"Timestamp -Redacted\">\n <wsu:Created>2018-01-10T00:00:00Z</wsu:Created>\n <wsu:Expires>2023-03-31T23:59:59Z</wsu:Expires>\n </wsu:Timestamp>\n <wsse:UsernameToken wsu:Id=\"SecurityToken-Redacted\">\n <wsse:Username>UserName</wsse:Username>\n <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">PASSWORD</wsse:Password>\n </wsse:UsernameToken>\n </wsse:Security>\n <tyl:ApiMessageContext>\n <tyl:SystemEnvironment>MySiteTest</tyl:SystemEnvironment>\n <tyl:RetryCount> 0 </tyl:RetryCount>\n <tyl:AllowFaults> true </tyl:AllowFaults>\n </tyl:ApiMessageContext>\n </soap:Header>\n <soap:Body>\n <tyl:ApiTxnExecutionSyncXml>\n <tyl:apiMessageData>\n <Transaction ReferenceNumber=\"IKJT1\" Source=\"IKJT\" TransactionType=\"IKJTEx\" >\n <Message MessageType=\"FindCase\" NodeID=\"12\" ReferenceNumber=\"R-19293\" UserID=\"5235126\" Source=\"Vendor\">\n <Options>\n <Nodes>\n <All>True</All>\n </Nodes>\n <CaseCategories>\n <All>True</All>\n </CaseCategories>\n <CaseTypes>\n <All>True</All>\n </CaseTypes>\n </Options>\n <SearchCriteria>\n <Case>\n <CaseNumber>123456</CaseNumber>\n </Case>\n </SearchCriteria>\n </Message>\n </Transaction>\n </tyl:apiMessageData>\n </tyl:ApiTxnExecutionSyncXml>\n </soap:Body>\n </soap:Envelope>\n "); return envelope; }
生成独立Message的代码
public XmlDocument SOAPReqBody() { XmlDocument body = new XmlDocument(); body.LoadXml( @"<Message MessageType=\"Config\">\n <Options>\n <Nodes>\n <All>True</All>\n </Nodes>\n </Options>\n <SearchCriteria>\n <Case>\n <CaseNumber>125487</CaseNumber>\n </Case>\n </SearchCriteria>\n </Message>" ); return body; }
原合并代码
public XmlDocument CallXML() { XmlDocument envelope = SoapRequestEnvelope(); XmlDocument body = SOAPReqBody(); XmlNode bodyNode = body.DocumentElement; XmlNode envelopeNode = envelope.SelectSingleNode("descendant::Transaction"); XmlElement root = envelope.DocumentElement; Console.WriteLine(envelopeNode); envelopeNode.AppendChild(bodyNode); return (envelope); }
错误原因
异常的核心是:不同XmlDocument实例的节点无法直接操作。bodyNode属于SOAPReqBody()创建的文档实例,envelopeNode属于SoapRequestEnvelope()创建的另一个文档实例,二者上下文不匹配,直接调用AppendChild会触发异常。
解决方案
使用XmlDocument.ImportNode()方法将外部节点导入到目标文档的上下文,该方法会创建一个适配当前文档的节点副本,之后即可正常添加到目标节点下。
针对长期目标(将信封XML移至外部文件加载),只需将envelope.LoadXml()替换为envelope.Load("路径/信封文件.xml")即可,合并逻辑无需修改。
修改后的合并代码
public XmlDocument CallXML() { XmlDocument envelope = SoapRequestEnvelope(); XmlDocument body = SOAPReqBody(); XmlNode bodyNode = body.DocumentElement; XmlNode envelopeNode = envelope.SelectSingleNode("descendant::Transaction"); // 关键步骤:导入外部节点到当前文档上下文,第二个参数true表示递归导入所有子节点 XmlNode importedNode = envelope.ImportNode(bodyNode, true); envelopeNode.AppendChild(importedNode); return envelope; }
添加多个Message节点的示例
如果需要添加多个<Message>,重复执行导入-添加流程即可:
public XmlDocument CallXMLWithMultipleMessages() { XmlDocument envelope = SoapRequestEnvelope(); XmlNode transactionNode = envelope.SelectSingleNode("descendant::Transaction"); // 添加第一个Message XmlDocument msg1Doc = SOAPReqBody(); XmlNode importedMsg1 = envelope.ImportNode(msg1Doc.DocumentElement, true); transactionNode.AppendChild(importedMsg1); // 添加第二个Message(假设有另一个生成Message的方法) XmlDocument msg2Doc = GetAnotherMessage(); XmlNode importedMsg2 = envelope.ImportNode(msg2Doc.DocumentElement, true); transactionNode.AppendChild(importedMsg2); return envelope; } // 示例:生成另一个Message的方法 public XmlDocument GetAnotherMessage() { XmlDocument doc = new XmlDocument(); doc.LoadXml(@"<Message MessageType=\"UpdateCase\">\n <CaseData>\n <CaseNumber>765432</CaseNumber>\n <Status>Closed</Status>\n </CaseData>\n </Message>"); return doc; }
内容的提问来源于stack exchange,提问作者BenStark
相关产品推荐
相关产品推荐

