调用WebService第三方ImportData方法时遇InvalidOperationException错误求助
我需要通过SOAP XML格式向第三方应用发送数据,已添加其WSDL引用,目标ImportData方法可用,该方法包含一个CDATA类型的参数。在SOAPUI中测试请求和响应一切正常,数据能成功插入第三方应用;但在WCF中构造CDATA并调用ImportData方法时,抛出InvalidOperationException错误。
错误信息
InvalidOperationException: The top XML element 'Response' from namespace '' references distinct types System.String and System.Object. Use XML attributes to specify another XML name or namespace for the element or types.
SOAPUI请求示例
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:sec=http://schemas.xmlsoap.org/ws/2003/06/secext xmlns:wsu=http://schemas.xmlsoap.org/ws/2003/06/utility xmlns:urn="urn:ThirdParty"> <soapenv:Header> <sec:Security> <sec:UsernameToken wsu:Id="ThirdParty"> <sec:Username>abcd</sec:Username> <!--Optional:--> <sec:Password>abcd</sec:Password> </sec:UsernameToken> </sec:Security> </soapenv:Header> <soapenv:Body> <urn:ImportData> <Table>Persons</Table> <FolderId>0</FolderId> <Data><![CDATA[<Document> <Record> <FirstName>Test USer</FirstName> <LastName>Test USer</LastName> <IsMainRole>Yes</IsMainRole> <IsHomeSite>Yes</IsHomeSite> <AccountStatus>System Administrator</AccountStatus> <IsClient/> <UserId>test_user</UserId> <Email>testuser@testuser.com</Email> <UserName>test_user</UserName> <HOFirstAxis>None</HOFirstAxis> <ModulesIMS>2</ModulesIMS> <InspectionType/> <RoleName>Main</RoleName> <Extra>mmeyers</Extra> <FunctionalGroups/> <SelectAllCalendarsByDefault>Yes</SelectAllCalendarsByDefault> <GroupNameho><None></GroupNameho> <GroupNameTCK><None></GroupNameTCK> <GroupNameIMS><None></GroupNameIMS> <GroupNameacs><None></GroupNameacs> <GroupNameAP><None></GroupNameAP> <GroupNameMoC><None></GroupNameMoC> <GroupNameRCM><None></GroupNameRCM> <DisplayUserLang>English</DisplayUserLang> <UseUserRS>No</UseUserRS> <TimeZone/> </Record> </Document>]]></Data> <FormatType>3</FormatType> <CSVSeparator>1</CSVSeparator> <FormatOptions>22</FormatOptions> <ImportType>2</ImportType> <MatchType>1</MatchType> <ImportOptions>1234</ImportOptions> </urn:ImportData> </soapenv:Body> </soapenv:Envelope>
WCF代码示例
[WebMethod] [SoapHeader("header", Direction = SoapHeaderDirection.InOut)] public string CreateXmlForImport() { ThirdPartyClient client = new ThirdPartyClient(); const string FILENAME = @"test.xml"; XDocument doc = XDocument.Load(FILENAME); XNamespace nsUrn = doc.Root.GetNamespaceOfPrefix("urn"); XElement importData = doc.Descendants(nsUrn + "ImportData").FirstOrDefault(); XElement xCdata = new XElement("Document", new XElement("Record", new XElement("UserName", "T12345"), new XElement("FirstName", "TEST_RP"), new XElement("LastName", "Test_LNAME"), new XElement("Email", "test@test.com") )); string cDataStr = xCdata.ToString(); XCData cdata = new XCData(cDataStr); var response = client.ImportData(cDataStr); return response; }
解决方案
问题根源
- WCF客户端代理生成时,错误解析了
ImportData的返回值或参数类型,导致XML序列化出现类型冲突。 - 代码直接传入字符串
cDataStr,WCF默认会对字符串做XML转义,而非包裹成CDATA节点,引发服务端解析异常,返回不符合预期的响应,进而触发序列化错误。 - WCF调用时未传入SOAPUI请求中的完整参数(如
Table、FolderId等),服务端返回异常响应,导致序列化失败。
修复步骤
正确构造CDATA并指定序列化方式
避免直接传入字符串,通过XmlCDataSection构造CDATA节点,并使用自定义数据契约确保WCF将参数序列化为CDATA格式:// 匹配接口定义的请求数据契约 [DataContract(Name = "ImportData", Namespace = "urn:ThirdParty")] public class ImportDataRequest { [DataMember(Name = "Table")] public string Table { get; set; } [DataMember(Name = "FolderId")] public int FolderId { get; set; } [DataMember(Name = "Data")] public XmlNode Data { get; set; } [DataMember(Name = "FormatType")] public int FormatType { get; set; } // 按需添加其他参数 } // 重构调用逻辑 public string CreateXmlForImport() { ThirdPartyClient client = new ThirdPartyClient(); XElement xCdata = new XElement("Document", new XElement("Record", new XElement("UserName", "T12345"), new XElement("FirstName", "TEST_RP"), new XElement("LastName", "Test_LNAME"), new XElement("Email", "test@test.com") )); // 构造CDATA节点 XmlDocument xmlDoc = new XmlDocument(); XmlCDataSection cdataNode = xmlDoc.CreateCDataSection(xCdata.ToString()); XmlElement dataElement = xmlDoc.CreateElement("Data"); dataElement.AppendChild(cdataNode); ImportDataRequest request = new ImportDataRequest { Table = "Persons", FolderId = 0, Data = dataElement, FormatType = 3, // 填充剩余必填参数 }; var response = client.ImportData(request); return response; }修正WCF客户端代理类型
重新生成客户端代理(使用svcutil.exe或添加服务引用时勾选"始终生成消息契约"),确保参数和返回值类型与WSDL定义一致。若返回值的Response元素存在类型冲突,手动调整数据契约属性:[XmlRoot(Namespace = "urn:ThirdParty", ElementName = "Response")] public class ImportDataResponse { [XmlElement(ElementName = "Result")] public string Result { get; set; } }传入完整参数
确保调用ImportData时传入SOAPUI请求中的所有必填参数(如CSVSeparator、ImportType等),避免服务端返回异常响应。
内容的提问来源于stack exchange,提问作者RKh

