PRB:InfoPath 无法自动向 Web 服务提交结构化 XML 数据

针对 Office 2003 的支持已终止

Microsoft 已于 2014 年 4 月 8 日终止了针对 Office 2003 的支持。该更改已影响到您的软件更新和安全选项。 了解这一措施对于您的含义以及如何继续保持受保护状态。

本文已归档。它按“原样”提供,并且不再更新。
症状
当您使用内置的 InfoPath 提交功能将 InfoPath 表单中的信息提交给 Web 服务时,可能会遇到下列症状之一:
  • 您可能收到一条错误消息。您收到的错误消息根据所提交的信息和在 Web 服务上调用的方法的编码而不同。

    - 或者 -
  • 您可能注意到将意外数据提交给了 Web 服务。
本文还讨论下列内容:
  • InfoPath 如何将数据提交给 Web 服务。
  • 将 InfoPath 表单的内容提交给 Web 服务的两种方法。
原因
当 InfoPath 向 Web 服务提交数据时,它将提交被选作参数的 XML 节点的内容,但是它不会提交 XML 节点本身。这通常会正常工作。例如,您有类似下面的 Web 服务方法:
[WebMethod]   public void SendSampleString( string sampleString )   {      //Do something interesting with the sample string.   } 
如果您将以下 XML 元素提交给此 Web 服务方法,sampleString 参数将被填入 "Hello, World!"(像您期望的那样)。
<sampleElement>"Hello, World!"</sampleElement>
遗憾的是,这种情况使得很难将 XML 节点或整个 InfoPath 表单提交给 Web 服务。例如,您有类似下面的 Web 服务方法:
[WebMethod]   public string SendXMLElement( System.Xml.XmlElement theElement )   {      //Report how many children the submitted node had.      return "Node with " + theElement.ChildNodes.Count + " children submitted.";   }
如果您使用内置的 InfoPath 提交功能将示例 XML 元素提交给此方法,则 theElement 参数的内容将生成错误。出现此错误的原因是只有 XML 元素的内容 ("Hello, World!") 被发送给此 Web 服务方法。因为该字符串不是有效的 XML 元素,所以 .NET Framework 会生成错误;错误消息显示在 InfoPath 中。

如果您尝试将整个 InfoPath 表单提交给示例 Web 服务方法,则会出现类似的问题。在这种情况下,InfoPath 会提交 InfoPath 表单的所有子节点,但不会提交根节点。这导致多个顶层 XML 节点被提交。因为这也不是有效的 XML,所以 .NET Framework 选择第一个顶层 XML 节点并将它用作 theElement 参数。所有其他节点都被忽略,这造成它们没有被提交的表象。
解决方案
要避免此问题,请在脚本中编写自定义提交操作。您可以使用下列方法之一:
  • 使用辅助数据源来执行提交操作。

    - 或者 -
  • 编写用于创建自定义 SOAP 消息并将其发送给 Web 服务的代码。

使用辅助数据源

  1. 在“工具”菜单上,单击“辅助数据源”。
  2. 辅助数据源对话框中,单击“添加”。
  3. 在“数据源设置向导”的第一页上,单击“Web 服务”,然后单击“下一步”。
  4. 输入您要提交的 Web 服务的位置,然后单击“下一步”。
  5. 选择您要使用的 Web 服务方法,然后单击“下一步”。
  6. 当 InfoPath 提示您从表单中选择将用于填充 Web 服务方法的参数的域或组时,请保留这些参数为空,然后单击“下一步”。
  7. 单击以清除“当表单打开时连接到此辅助数据源”复选框,单击“完成”,然后单击“确定”关闭辅助数据源对话框。
  8. 在“工具”菜单上,单击“提交表单”。
  9. 在“提交表单”对话框中,单击“启用提交”。
  10. 在“提交”列表中,单击“使用自定义脚本提交”,然后单击“确定”打开 Microsoft 脚本编辑器。
  11. XDocument::OnSubmitRequest 方法中,使用与以下脚本类似的脚本提交整个表单。

    注意:您还可以提交表单中的个别元素。
    try{      //Get a reference to the SendXMLElement secondary data source.      var objSendXMLElement = XDocument.GetDOM("SendXMLElement");      objSendXMLElement.setProperty( "SelectionNamespaces",         'xmlns:s1="http://joelallxp.microsoft.com/schema" ' +         'xmlns:s0="http://tempuri.org/" ' +         'xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"' );       //Remove any data from the SendXMLElement secondary data source.      var objData = objSendXMLElement.selectSingleNode(         "/dfs:myFields/dfs:queryFields/s0:SendXMLElement/s0:theElement");      var objCurrentData = objData.selectNodes("@* | node()");      objCurrentData.removeAll();       //Clone the XDocument.      var objClonedDocument = XDocument.DOM.documentElement.cloneNode(true );      objData.appendChild( objClonedDocument );         //Call the "Query" method of the secondary data source to send the data.      XDocument.DataObjects("SendXMLElement").Query();         //Report the results of the submit.      XDocument.UI.Alert(          objSendXMLElement.selectSingleNode(            "/dfs:myFields/dfs:dataFields/s0:SendXMLElementResponse/s0:SendXMLElementResult").text );      eventObj.ReturnStatus = true;   }   catch(ex)   {      eventObj.ReturnStatus = false;   }

编写代码

  1. 在“工具”菜单上,单击“提交表单”。
  2. 在“提交表单”对话框中,单击“启用提交”。
  3. 在“提交”列表中,单击“使用自定义脚本提交”,然后单击“确定”打开 Microsoft 脚本编辑器。
  4. XDocument::OnSubmitRequest 方法中,使用与以下脚本类似的脚本提交整个表单。

    注意:您还可以提交表单中的个别元素。
    try   {       //Create a SOAP object.      var objSOAPConnector = new ActiveXObject("MSOSOAP.HttpConnector30");         //Set the EndPointURL property to point to the Web service.      objSOAPConnector.Property("EndPointURL") = "http://server/WebService1/Submit.asmx";       //Set the SoapAction property to point to the Web service method. You can find this URI       //in the WSDL file of the Web service.      objSOAPConnector.Property("SoapAction") = "http://tempuri.org/SendXMLElement";      objSOAPConnector.Connect();            //Begin construction of a SOAP message to send to the Web service.      objSOAPConnector.BeginMessage();       var objSOAPSerializer = new ActiveXObject("MSOSoap.SoapSerializer30");      objSOAPSerializer.Init( objSOAPConnector.InputStream );      objSOAPSerializer.startEnvelope();      objSOAPSerializer.startBody();       //Construct the structure that marks the method name and the parameter name       //that you are sending.      objSOAPSerializer.StartElement( "SendXMLElement", "http://tempuri.org/" );      objSOAPSerializer.StartElement( "theNode", "http://tempuri.org/" );       //Write out the XML of the document.      objSOAPSerializer.WriteXml( XDocument.DOM.documentElement.xml );       //Finish each element.      objSOAPSerializer.EndElement();      objSOAPSerializer.EndElement();       //Call EndMessage to complete the SOAP message and send it to the Web service method.      //This results in the Web service method being called.      objSOAPSerializer.endBody();      objSOAPSerializer.endEnvelope();       objSOAPConnector.EndMessage();       //Use a SoapReader to read the response from the Web service method .      var ResponseReader = new ActiveXObject("MSOSOAP.SoapReader30");      ResponseReader.Load( objSOAPConnector.OutputStream );       //If there was no error, return true.      if (ResponseReader.Fault != null)      {         eventObj.ReturnStatus = false;         throw "Error submitting data: " + ResponseReader.Fault.xml;      }      eventObj.ReturnStatus = true;   }    catch (ex)   {       XDocument.UI.Alert("Failed to submit document: " + ex.description);    }
这种现象是设计所导致的。
更多信息

重现问题的步骤

  1. 创建一个包含下面两个方法的 Web 服务:
    • 方法 1
      [WebMethod]   public void SendSampleString( string sampleString )   {      //Do something interesting with the sample string.   } 
    • 方法 2
      [WebMethod]   public string SendXMLElement( System.Xml.XmlElement theElement )   {      //Report how many children the submitted node had.      return "Node with " + theElement.ChildNodes.Count + " children submitted.";   }
  2. 通过选择“从数据源新建”来设计新的 InfoPath 表单。
  3. 在“数据源设置向导”中,选择“Web 服务”,然后单击“下一步”。
  4. 单击“接收和提交数据”,然后单击“下一步”。
  5. 对于接收数据 Web 服务方法,请按照下列步骤操作:
    1. 输入您先前创建的 Web 服务的 URL,然后单击“下一步”。
    2. 在“选择操作”列表中,单击“SendXMLElement”,然后单击“下一步”。
  6. 对于提交数据 Web 服务方法,请按照下列步骤操作:
    1. 输入您先前创建的 Web 服务的 URL,然后单击“下一步”。
    2. 在“选择操作”列表中,单击“SendXMLElement”,然后单击“下一步”。
  7. 单击“修改”按钮为提交操作选择一个参数。
  8. 在“dataFields”列表中,单击“SendXMLElementResult”,单击“确定”,然后单击“下一步”。
  9. 单击“先设计数据视图”,然后单击“完成”关闭“数据源设置向导”对话框。
  10. 向表单中添加 SendXMLElementResult 域。
  11. 预览表单。
  12. 发送 XML 节点结果控件中,键入 Hello, World!
  13. 在“文件”菜单上,单击“提交”。

    您将收到下面的错误消息:
    InfoPath cannot submit the form.
    An error occurred while the form was being submitted.

    Show Details:
    The SOAP response indicates that an error occurred:
    Server was unable to read request.--> There is an error in XML document (1,409).-->Specified cast is not valid.
  14. 关闭“预览”窗口,然后使表单返回设计模式。
要解决此问题,请使用本文“解决办法”一节中提到的任一方法。
属性

文章 ID:826989 - 上次审阅时间:01/11/2015 05:20:26 - 修订版本: 3.2

Microsoft Office InfoPath 2003

  • kbnosurvey kbarchive kbbug kbprb KB826989
反馈