Up to this point, we have focused on solutions that have taken advantage of the direct submission features of InfoPath. For some solutions, this won t be the correct implementation. InfoPath enables you to submit forms through either custom scripts or a generic HTTP POST.
When an InfoPath document submits an XML document to a Web Service, the default behavior posts the contents of the individual nodes. This is a design feature that enables parameter-based field submission to the back-end Web Service. If the form designer wants to bypass this and submit the entire XML document, then he can enable a custom submit scripting routine by using the Submit options shown in Figure 4.23.
When enabled, XML submission occurs through the OnSubmitRequest function maintained as part of the application s solution file. For example, the script block shown in Listing 4.9 submits an entire XML request to a Web Service.
try{ //Get a reference to the SendXMLNode secondary data source var objSendXMLNode = XDocument.GetDOM("SendXMLNode"); objSendXMLNode.setProperty( "SelectionNamespaces", 'xmlns:s1="http://mycompany.schema.com/schema" ' + 'xmlns:s0="http://tempuri.org/" ' + 'xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/data FormSolution"' ); //Remove any data from the SendXMLNode secondary data source var objData = objSendXMLNode.selectSingleNode( "/dfs:myFields/dfs:queryFields/s0:SendXMLNode/s0:theNode"); 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("SendXMLNode").Query(); //Report the results of the submit XDocument.UI.Alert( objSendXMLNode.selectSingleNode( "/dfs:myFields/dfs:dataFields/s0:SendXMLNodeResponse/s0:SendXMLNodeResult").text ); eventObj.ReturnStatus = true; } catch(ex) { eventObj.ReturnStatus = false; }
Another custom submission option is to use a custom SOAP message, shown in Listing 4.10. In this scenario, the form designer can define a custom message using the SOAP library and HTTP.
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/SendXMLNode"; 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 parameter name we're sending objSOAPSerializer.StartElement( "SendXMLNode", "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); }
In this example, the custom SOAP message is instantiated using the ActiveXObject method of the XDocument object model.
Many times, an existing InfoPath application may become a part of an existing Web-based application. This includes posting to specific pages and then allowing the page to do something with the data. When InfoPath posts to an HTTP address, the form data is actually contained as part of the binary stream. This means that as part of a post request, Web developers cannot access it within a Web page using either the form or variables collection. In order to access the posted data, developers use the readbinary method of the request object to retrieve the byte array that contains the data. Once retrieved, this data can be converted to a string and then processed on the Web page.
ASP.NET provides a low-level request/response API that enables developers to use the .NET Framework classes to service incoming HTTP requests . This is provided in the System.Web.IHTTPHandler interface and implements the Process Request method. These handler types are useful when the services provided by the high-level page framework abstraction are not required for processing an HTTP request.
Each incoming HTTP request received by ASP.NET is ultimately processed by a specific instance of a class that implements IHTTPHandler . The IHTTPHandlerFactory provides the infrastructure that handles the actual resolution of URL requests to IHTTPHandler instances. In addition to the default IHTTPHandlerFactory classes provided by ASP.NET, developers can create and register factories to support their own request resolution and activation scenarios.
Using InfoPath, you can have a form provide a post request using HTTP by editing the form properties and selecting HTTP with the URL of the page that you want to submit the request to, as shown in Figure 4.24.
Within the page load event, we could add the code in Listing 4.11, which shows the submitted response of the Interview Feedback form in an ASP.NET Web Form DataGrid .
Dim binread As Byte() Dim bytecount As Integer bytecount = Request.TotalBytes binread = Request.BinaryRead(bytecount) 'Converts the binary data to a string. Dim i As Integer Dim temp As Byte() Dim spost As String For i = 0 To (Request.TotalBytes - 1) spost = spost & Chr(binread(i)) Next 'Response.Write(spost) If spost = "" Then Page.Response.Write("Nothing to show") Else Dim stream As System.IO.StringReader Dim reader As System.Xml.XmlTextReader = Nothing stream = New System.IO.StringReader(spost) Dim ds As New System.Data.DataSet ds.ReadXml(stream) DataGrid1.DataSource = ds DataGrid1.DataBind() End If
This code grabs the binary stream of data and reads the request. This request data is then bound to the DataGrid object and displayed using an ASP.NET page.