Steps to reproduce the behavior
- In Microsoft Visual Studio .NET, create a new Microsoft C# ASP.NET Web service project. Change the name of this project to NorthwindDataSet.
You can do this by changing the location to http://localhost/NorthwindDataSet. - On the Project menu, click Add Web Service. Name the new Web service CustomerInfo.asmx.
- Add the following code to the new CustomerInfo.asmx Web service:
/************************************************************************
* GetCustomerInfo -- This method retrieves information from the
* Customer table of the Northwind database and then returns it in an
* ADO.NET DataSet.
* Parameters: CustomerID is the string that contains the CustomerID of the
* customer to retrieve the information for.
* Returns: An ADO.NET DataSet that contains information about the customer.
* *********************************************************************/
[WebMethod]
public System.Data.DataSet GetCustomerInfo( string CustomerID )
{
try
{
//Create a Microsoft SQL Server connection to the local SQL Server.
System.Data.SqlClient.SqlConnection theConnection = new SqlConnection();
theConnection.ConnectionString = "Data Source=(local);" +
"Integrated Security=SSPI;Initial Catalog=northwind";
//Create an SQL Command to query the data.
System.Data.SqlClient.SqlCommand theCommand = new SqlCommand();
theCommand.Connection = theConnection;
theCommand.CommandText = "SELECT \"CustomerID\",\"CompanyName\"," +
"\"ContactName\",\"ContactTitle\",\"Address\",\"City\",\"Region\"," +
"\"PostalCode\",\"Country\",\"Phone\",\"Fax\" FROM \"Customers\" " +
"WHERE CustomerID='" + CustomerID + "'";
//Create an SQL DataAdapter to read the data.
System.Data.SqlClient.SqlDataAdapter theDataAdapter = new SqlDataAdapter();
theDataAdapter.SelectCommand = theCommand;
//Open the command, and then read the data.
theConnection.Open();
System.Data.DataSet theCustomerInfo = new DataSet();
theCustomerInfo.DataSetName = "CustomerInfo";
theCustomerInfo.Namespace = "http://localhost/NorthwindDataSet/CustomerInfo";
theDataAdapter.Fill( theCustomerInfo, "Customers" );
//Clean up.
theConnection.Close();
//Return the result.
return theCustomerInfo;
}
catch(Exception ex)
{
return null;
}
}
The sample code tries to connect to a computer that is running Microsoft SQL Server on the same computer as the Web service. Alternatively, you can change the connection string that is used by the System.Data.SqlConnection object to connect to a different computer that is running SQL Server. You may have to configure SQL Server permissions to permit the Web service to access the database.
For additional information, click the following article number to view the article in the Microsoft Knowledge Base:
815154�
HOW TO: Configure SQL Server Security for .NET Applications
- At the top of the CustomerInfo.asmx.cs page, add the following code to the USING statements:
using System.Data.SqlClient;
- Compile the NorthwindDataSet project.
- Start InfoPath. On the File menu, click Design a Form.
- In the Design a Form task pane, click New from Data Source.
- In the Data Source Setup Wizard dialog box, select Web Service as the type of data source, and then click Next.
- Select Receive Data, and then click Next.
- Type the URL to the CustomerInfo Web service (for example, http://localhost/NorthwindDataSet/CustomerInfo.asmx), and then click Next.
- Select the GetCustomerInfo method for the operation, and then click Next.
- Select the s0:CustomerID parameter, and then click Set Sample Value.... In the Set Value dialog box, type ALFKI, and then click OK.
- Click Next.
Note InfoPath displays the error message that is in the "Symptoms" section.
Workarounds
To work around the problem, you can use steps that are similar to the following steps to add a new Web service method that removes the incompatible elements from the XML of the ADO.NET DataSet. You do this so that the XML data can be used by InfoPath. The Web service method can remove the inline schema information from the XML data, or the Web service method can serialize the XML data in a strongly typed wrapper class and return that.
Each method has advantages and disadvantages.
Workaround 1
Remove the Inline Schema and the Incompatible XML Attributes
This work around is good because it is simple to implement. Additionally, if the XML data that the original Web service returns changes for any reason, this workaround requires no changes to work with the new data.
However, this workaround also has a disadvantage. This workaround does not describe the schema of the XML data. Therefore, InfoPath must infer the schema from sample data. If the sample data does not contain all the possible elements and attributes that the Web service method can return, the schema that InfoPath infers will not contain those elements. If you run a query that returns elements or attributes that are not in the sample call, InfoPath displays an error.
To implement Workaround 1, follow these steps:
- In Visual Studio .NET, open the NorthwindDataSet project.
- On the Project menu, click Add Web Service. Name the new Web service IPCustomerInfo.asmx.
- Add the following code to the new IPCustomerInfo.asmx Web service:
/************************************************************************
* GetCustomerInfoNoSchema: This method calls the GetCustomerInfo
* method of the CustomerInfo.asmx Web service, and then strips the
* inline schema from the resulting DataSet.
* Parameters: CustomerID is the string that contains the CustomerID of the
* customer to retrieve information for.
* Returns: An XML Document with no inline schema.
* *********************************************************************/
[WebMethod]
public System.Xml.XmlDocument GetCustomerInfoNoSchema( string CustomerID )
{
//Get the core data.
CustomerInfo theCustomerInfoService = new CustomerInfo();
System.Data.DataSet theDataSet =
theCustomerInfoService.GetCustomerInfo( CustomerID );
//Create a new XmlDocument from the data of the dataset.
System.Xml.XmlDocument theDocument = new System.Xml.XmlDocument();
theDocument.LoadXml( theDataSet.GetXml() );
//Return the result.
return theDocument;
}
The sample code uses the original Web service to provide an ADO.NET DataSet and then creates a new XML document with no inline schema information. - Compile the NorthwindDataSet project.
- Start InfoPath. On the File menu, click Design a Form.
- In the Design a Form task pane, click New from Data Source.
- In the Data Source Setup Wizard dialog box, select Web Service as the type of data source, and then click Next.
- Select Receive Data, and then click Next.
- Type the URL to the IPCustomerInfo Web service (for example, http://localhost/NorthwindDataSet/IPCustomerInfo.asmx), and then click Next.
- Select the GetCustomerInfoNoSchema method for the operation, and then click Next.
- Select the s0:CustomerID parameter, and then click Set Sample Value. In the Set Value dialog box, type ALFKI, and then click OK.
- Click Next, and then click Finish.
- Move the CustomerID field from the queryFields group in the Data Source task pane, and then add the CustomerID field to the Query view.
- Move the Customers group from the dataFields group in the Data Source task pane, and then add the Customers group to the Data Entry view. Click Section with controls.
- Preview, and then test the form. Notice that for some customer IDs such as QUEEN, the query encounters errors because the sample data does not contain all the possible elements that the Web service can return.
Workaround 2
Create a Strongly-Typed Wrapper Class to Serialize the XML Data of the ADO.NET DataSet
This workaround is more difficult to implement than the previous workaround. Additionally, this workaround must be tailored to each Web service method that it is used with, and that Web service method must not change the schema of the data that it returns. However, this workaround describes the schema of the XML data that it returns. Therefore, InfoPath does not have to infer the structure of the data. As a result, InfoPath forms that are created from this workaround are not susceptible to errors that are caused by optional elements and attributes.
- In Microsoft Internet Explorer, move to the URL of the CustomerInfo Web service test page (for example, http://localhost/NorthwindDataSet/CustomerInfo.asmx).
- Click GetCustomerInfo to move to the test page for that method.
- In the CustomerID text box, enter ALFKI, and then click Invoke.
- From the XML that results, copy the <xs:schema> element and all its children, and then paste them in a new text document in Notepad.
- Remove the - characters from the pasted text, and then save the document as CustomerInfo.xsd.
- Open a Visual Studio .NET command prompt, and move to the directory where you saved CustomerInfo.xsd.
- Use the following line to create a wrapper class from the schema file:
xsd.exe CustomerInfo.xsd /c /l:cs
- In Visual Studio .NET, open the NorthwindDataSet project.
- On the Project menu, click Add Existing Item.
- Move to the CustomerInfo.cs file that you created with the Xsd.exe tool, and then click Open.
- Add the namespace CustomerInfoWrapper around the CustomerInfo class and the CustomerInfoCustomers class.
- Add the following code to the IPCustomerInfo.asmx Web service:
/************************************************************************
* GetCustomerInfoWrapper: This method calls the GetCustomerInfo
* method of the CustomerInfo.asmx Web service, and then strips the
* inline schema from the resulting DataSet.
* Parameters: CustomerID is the string that contains the CustomerID of the
* customer to retrieve information for.
* exampleData is the wrapper class to fill with the data from the
* ADO.NET DataSet.
* Returns: none
* *********************************************************************/
[WebMethod]
public void GetCustomerInfoWrapper( string CustomerID,
out CustomerInfoWrapper.CustomerInfo exampleData )
{
//Get the core data.
CustomerInfo theCustomerInfoService = new CustomerInfo();
System.Data.DataSet theDataSet =
theCustomerInfoService.GetCustomerInfo( CustomerID );
theDataSet.Namespace = "http://localhost/NorthwindDataSet/CustomerInfo";
//Create an in-memory stream to write the DataSet to.
System.IO.MemoryStream theStream = new System.IO.MemoryStream();
//Write the DataSet to the stream.
theDataSet.WriteXml( theStream, XmlWriteMode.IgnoreSchema );
//Move the streams seek pointer back to the beginning, or
//deserialization will fail.
theStream.Seek(0, System.IO.SeekOrigin.Begin );
//Create an XML Serializer to read the DataSet.
System.Xml.Serialization.XmlSerializer ser = new
System.Xml.Serialization.XmlSerializer(
typeof(CustomerInfoWrapper.CustomerInfo));
//Deserialize a CustomerInfo wrapper from the stream.
exampleData = ((CustomerInfoWrapper.CustomerInfo)
(ser.Deserialize( theStream )));
return;
}
The sample code uses the original Web service to provide an ADO.NET DataSet, and then creates a new XML document with no inline schema information. - Compile the NorthwindDataSet project.
- Start InfoPath. On the File menu, click Design a Form.
- On the Design a Form task pane, click New from Data Source...
- In the Data Source Setup Wizard dialog box, select Web Service as the type of data source, and then click Next.
- Select Receive Data, and then click Next.
- Type the URL to the IPCustomerInfo Web service (for example, http://localhost/NorthwindDataSet/IPCustomerInfo.asmx), and then click Next.
- For the operation, select the GetCustomerInfoWrapper method, and then click Next.
Notice that InfoPath does not prompt you to specify sample values for the Web service method. - Click Finish.
- Move the CustomerID field from the queryFields group in the Data Source task pane, and then add the CustomerID field to the Query view.
- Move the Customers group from the dataFields group in the Data Source task pane, and then add the Customers group to the Data Entry view.
- Preview and then test the form.
Notice that any valid customer ID works in this form.