BUG: A Typed DataSet That Imports a Secondary Schema Cannot be Used As a Method Parameter or As a Return Type with ASP.NET Web Services (317340)



The information in this article applies to:

  • Microsoft Web Services (included with the .NET Framework)

This article was previously published under Q317340

SYMPTOMS

You cannot create a Web service proxy when the Typed DataSet that imports a secondary schema is used as a parameter or as a return type from the WebMethod. If you try to do this, the following symptoms may occur:
  • When you generate the Web service proxy class by using the Web Services Description Language (WSDL) tool, WSDL.exe fails. You receive the following warning message and error message:
    Warning: Schema could not be validated. Class generation may fail or may produce incorrect results.
    Error generating DataSet for schema 'SchemaNamespace'.
    where 'SchemaNamespace' is the namespace of the schema.
  • The Visual Studio .NET Web References wizard does not produce a Web service proxy for your Web service. No errors are reported. However, you find that the References.cs file or the References.vb file (that contains the proxy definition) do not exist. Also, the client application cannot declare instances of the Web service proxy.

CAUSE

When you create the Web service proxy that uses Typed DataSet, the Typed DataSet does not correctly import secondary schemas. Instead of using the expected secondary schema, the returned schema imports a schema with an arbitrary name such as _app1.xsd. Because of an incorrect secondary schema name, the tools such as WSDL.exe or Microsoft Visual Studio .NET cannot correctly create a proxy for the Web service. Also, the returned XML cannot be serialized back to a corresponding Typed DataSet instance. If you try to do this, the result is an XmlSchemaException.

WORKAROUND

To work around this problem, return the Typed DataSet that you want as an XmlElement in your WebMethod. In your client, you can explicitly load the returned XML to an instance of the Typed DataSet that you want. The following code is an example for WebMethod:

Visual Basic .NET
   <WebMethod()> Public Function GetTypedDataSet() As System.Xml.XmlElement
      ' Create an instance of Typed DataSet.
      Dim myDs As MyTypedDataSet = New MyTypedDataSet()

      ' Populate the DataSet with the Data.
      Dim myCn As New System.Data.SqlClient.SqlConnection("Persist Security Info=False;User ID=<username>;Password=<strong password>;Initial Catalog=pubs;Data Source=SQLServer;Packet Size=4096")
      myCn.Open()
      Dim myDa As New System.Data.SqlClient.SqlDataAdapter("Select * from Employee", myCn)
      myDa.Fill(myDs, myDs.Tables(1).TableName)

      ' Return the DataSet as an XmlElement.
      Dim xdd As System.Xml.XmlDataDocument = New System.Xml.XmlDataDocument(myDs)
      Dim docElem As System.Xml.XmlElement = xdd.DocumentElement
      Return docElem
   End Function
Visual C# .NET
		[WebMethod]
		public System.Xml.XmlElement GetTypedDataSet () 
		{
			// Create an instance of Typed DataSet.
			MyTypedDataSet myDs = new MyTypedDataSet ();
			
			// Add some data to the DataSet.
			System.Data.SqlClient.SqlConnection myCn =new System.Data.SqlClient.SqlConnection("Persist Security Info=False;User ID=<username>;Password=<password>;Initial Catalog=pubs;Data Source=SQLServer;Packet Size=4096");
			myCn.Open();
			System.Data.SqlClient.SqlDataAdapter myDa = new System.Data.SqlClient.SqlDataAdapter("Select * from Employee", myCn);
			myDa.Fill(myDs, myDs.Tables[1].TableName);

			// Return the DataSet as an XmlElement.
			System.Xml.XmlDataDocument xdd = new System.Xml.XmlDataDocument (myDs);
			System.Xml.XmlElement docElem = xdd.DocumentElement;   
			return docElem ;
		}
Modify the SQL connection string to access data from Microsoft SQL Server.

The following code shows the sample client that calls the WebMethod:

Visual Basic .NET
   Public Sub GetData()

      ' Create an instance of Typed DataSet.
      Dim ds As MyTypedDataSet = New MyTypedDataSet()

      ' Create an instance of Web service proxy.
      Dim WebProxy As MyWebServiceProxy = New MyWebServiceProxy()

      ' Get the data from Webservice
      Dim elem As XmlElement = WebProxy.GetTypedDataSet()

      ' Load the XML to the Typed DataSet that you want.
      Dim nodeReader As XmlNodeReader = New XmlNodeReader(elem)
      ds.ReadXml(nodeReader, XmlReadMode.Auto)

      ' Use Typed DataSet as you would typically do.
   End Sub
Visual C# .NET
public void GetData()
{
	// Create an instance of Typed DataSet.
	MyTypedDataSet ds = new MyTypedDataSet ();

	// Create an instance of Web service proxy.
	MyWebServiceProxy WebProxy = new MyWebServiceProxy () ;

	// Get the data from Webservice.
	XmlElement elem = WebProxy.GetTypedDataSet () ;

	// Load the XML to the Typed DataSet that you want.
	XmlNodeReader nodeReader = new XmlNodeReader (elem) ;
	ds.ReadXml (nodeReader, XmlReadMode.Auto) ;

	// Use Typed DataSet as you would typically do.
}

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Steps to Reproduce the Problem

  1. Save the following XSD schema file as c:\Employee.xsd:
    <?xml version="1.0" standalone="yes"?>
    <xs:schema id="MyTypedDataSet" targetNamespace="MyTypedDataSetNamespace" xmlns:mstns="MyTypedDataSetNamespace" xmlns="MyMyTypedDataSetDataSetNamespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified" elementFormDefault="qualified">
      <xs:element name="MyTypedDataSet" msdata:IsDataSet="true">
        <xs:complexType>
          <xs:choice maxOccurs="unbounded">
            <xs:element name="Employee">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="emp_id" type="xs:string" minOccurs="0" />
                  <xs:element name="fname" type="xs:string" minOccurs="0" />
                  <xs:element name="minit" type="xs:string" minOccurs="0" />
                  <xs:element name="lname" type="xs:string" minOccurs="0" />
                  <xs:element name="job_id" type="xs:short" minOccurs="0" />
                  <xs:element name="job_lvl" type="xs:unsignedByte" minOccurs="0" />
                  <xs:element name="pub_id" type="xs:string" minOccurs="0" />
                  <xs:element name="hire_date" type="xs:dateTime" minOccurs="0" />
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:choice>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    Note This is an XSD schema for the Employee table of the Pubs database of SQL Server.
  2. Save the following file as c:\SecondarySchema.xsd:
    <?xml version="1.0" standalone="yes"?>
    <xs:schema id="MySecDataSet" targetNamespace="MySecDataSetNamespace" xmlns:mstns="MySecDataSetNamespace" xmlns="MySecDataSetNamespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified" elementFormDefault="qualified">
      <xs:element name="EmployeeCity">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="City" type="xs:string" minOccurs="0" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  3. To import the SecondarySchema file, add the following code before the MyTypedDataSet element that is in the Employee.xsd file:
    <xs:import id ="XMLSchema11" namespace = "MySecDataSetNamespace" schemaLocation ="file:///c:\SecondarySchema.xsd" />
    
  4. Open the Visual Studio .NET command prompt and then change to the folder c:\.
  5. At the command prompt, type one of the following commands to create the Typed DataSet class file:
    1. For Visual Basic .NET, type: xsd.exe /d /l:vb Employee.xsd.

      The Employee.vb file is created.
    2. For Visual C# .NET, type: xsd.exe /d Employee.xsd.

      The Employee.cs file is created.
  6. In Visual Studio .NET, create a new ASP.NET Web service project that is named TestTypedDS by using Visual Basic .NET or Visual C# .NET.

    By default, Service1.asmx is created.
  7. On the Project menu, click Add Existing Item. Move to drive C and then select Employee.vb or Employee.cs.

    The file that you select depends on the language that you use in your project.
  8. In Solution Explorer, right-click Service1.asmx and then click View Code. Add the following code to create a WebMethod:

    For Visual Basic .NET:
       <WebMethod()> Public Function GetTypedDataSet() As MyTypedDataSet
          Dim myDs As New MyTypedDataSet()
          Dim myCn As New System.Data.SqlClient.SqlConnection("Persist Security Info=False;User ID=<username>;Password=<strong password>;Initial Catalog=pubs;Data Source=SQLServer;Packet Size=4096")
          myCn.Open()
          Dim myDa As New System.Data.SqlClient.SqlDataAdapter("Select * from Employee", myCn)
          myDa.Fill(myDs, myDs.Tables(1).TableName)
          Return myDs
       End Function
    For Visual C# .NET:
    		[WebMethod()] public MyTypedDataSet GetTypedDataSet()
    		{
    			MyTypedDataSet myDs = new MyTypedDataSet();
    			System.Data.SqlClient.SqlConnection myCn =new System.Data.SqlClient.SqlConnection("Persist Security Info=False;User ID=<username>;Password=<strong password>;Initial Catalog=pubs;Data Source=SQLServer;Packet Size=4096");
    			myCn.Open();
    			System.Data.SqlClient.SqlDataAdapter myDa = new System.Data.SqlClient.SqlDataAdapter("Select * from Employee", myCn);
    			myDa.Fill(myDs, myDs.Tables[1].TableName);
    			return myDs;
    		}
  9. Modify the SQL connection string to access data from your SQL Server.
  10. On the Debug menu, click Start to run the application.
  11. Click the TestDataSet link and then click Invoke.
  12. Verify that the secondary schema is incorrectly imported as _app1.xsd.
  13. Create a new ASP.NET Web Application project by using Visual Basic .NET or Visual C# .NET.
  14. In Solution Explorer, right-click References and then click Add Web Reference.
  15. In the Address text box, type http://localhost/TestTypedDS/Service1.asmx and then press ENTER.
  16. Click Add Reference.
  17. In Solution Explorer, right-click WebForm1.aspx and then click View Code.
  18. If you try to create an instance of the Web service proxy in the Page_Load event handler, you cannot. You cannot do this because the proxy class has not been generated correctly.

    Use the WSDL tool and try to create a Web service proxy class:
    1. At the Visual Studio .NET command prompt, type the following command: wsdl.exe "http://localhost/TestTypedDS/Service1.asmx?wsdl".
    2. Press ENTER.
    3. The error message in the Symptoms section appears.

REFERENCES

For additional information about creating Typed DataSet, click the following article numbers to view the articles in the Microsoft Knowledge Base:

315678 HOW TO: Create and Use a Typed DataSet by Using Visual Basic .NET

320714 HOW TO: Create and Use a Typed DataSet by Using Visual C# .NET


Modification Type:MajorLast Reviewed:11/7/2003
Keywords:kbWebServices kbSystemData kbSqlClient kbDataAdapter kberrmsg kbbug KB317340 kbAudDeveloper