1. 概述
    很多正在开发或者打算开发
xml Web Services的程序员都问过这样的一个问题:"我的Web Service
返回的结果是一个DataSet类型的对象,但如果我的客户端不是用.NET写的(因而没有内建的DataSet类型),那该如何调用这个Web Service并访问DataSet中的数据呢?"。  
  对于这个问题,首先应该说的是:1)在多种语言共存的编程环境下,是不适合使用类似DataSet这种只属于特定语言的数据类型的。不管是在
xml Web Services还是CORBA的环境中,都应该尽量使用简单数据类型以及简单数据类型的数组。2)应当很谨慎的决定是否需要通过Web Service来
返回大量数据。由于网络传输的开销既包括HTTP连接建立的时间,也包括传送数据的时间,因此需要在减少访问
服务器次数和减少网络传输量之间寻找一个合适的平衡。如非必须,则不适合通过Web Service传送含有几十条或者几百条数据的数据表。  
  然后,就问题本身而言,.NET Web Services
返回的DataSet类型是可以直接被其他非.NET的客户端解析的,因为即便是DataSet类型的
返回值,也会被表达成
xml格式再进行传输。下面的例子就是一个
返回类型为DataSet的Web Method,及其被调用后
返回的
xml格式数据:  
  表1. 
返回类型为DataSet的Web Method
  [WebMethod]
  public DataSet GetPersonData()
  {
  DataTable table=new DataTable("Person");
  table.Columns.Add("Name");
  table.Columns.Add("Gender");
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);  
  DataSet dataset=new DataSet("PersonTable");
  dataset.Tables.Add(table);
  return dataset;
  }  
  表2. 被格式化成
xml的DataSet
  <?
xml version="1.0" encoding="utf-8"?>
  <DataSet 
xmlns="http://tempuri.org/">
  <xs:schema id="PersonTable" 
xmlns="" 
xmlns:xs="http://www.w3.org/2001/
xmlSchema"  
xmlns:msdata="urn:schemas-microsoft-com:
xml-msdata">
  <xs:element name="PersonTable" msdata:IsDataSet="true" msdata:Locale="zh-CN">
  <xs:complexType>
  <xs:choice maxOccurs="unbounded">
  <xs:element name="Person">
  <xs:complexType>
  <xs:sequence>
  <xs:element name="Name" type="xs:string" minOccurs="0" />
  <xs:element name="Gender" type="xs:string" minOccurs="0" />
  </xs:sequence>
  </xs:complexType>
  </xs:element>
  </xs:choice>
  </xs:complexType>
  </xs:element>
  </xs:schema>
  <diffgr:diffgram 
xmlns:msdata="urn:schemas-microsoft-com:
xml-msdata"  
xmlns:diffgr="urn:schemas-microsoft-com:
xml-diffgram-v1">
  <PersonTable 
xmlns="">
  <Person diffgr:id="Person1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
  <Name>Alice</Name>
  <Gender>Female</Gender>
  </Person>
  <Person diffgr:id="Person2" msdata:rowOrder="1" diffgr:hasChanges="inserted">
  <Name>Bob</Name>
  <Gender>Male</Gender>
  </Person>
  <Person diffgr:id="Person3" msdata:rowOrder="2" diffgr:hasChanges="inserted">
  <Name>Chris</Name>
  <Gender>Male</Gender>
  </Person>
  </PersonTable>
  </diffgr:diffgram>
  </DataSet>  
  从上面的例子可以看出,直接使用DataSet作为
返回类型,其结果是相当复杂的,其中不但包含了DataSet中的数据,还包括了数据更改的信息,以及DataSet的Schema。虽然有些工具能够生成一个类似DataSet的客户端类型,但无论是直接解析复杂的
xml还是使用类似DataSet的类,都不够直接不够清晰。  
  解决这个问题的方案有两种:  
  1) 用简单数据类型构造自定义类型,用每一个自定义类型对象封装数据集中的一行,将自定义类型对象的数组(Array)
返回客户端;由于是用简单数据类型定义,客户端能够完全不变的还原出自定义类型的定义;  
  2) 用DataSet.Write
xml()方法将数据集中的数据提取成
xml格式,并以字符串的形式
返回给客户端,再由客户端解析
xml字符串,还原出数据。由于使用Write
xml()的时候能够过滤掉冗余信息,
返回的内容和图表2中的内容相比大大简化了。    
2. 创建.NET Web Services,返回数据集合    借助于Visual Studio.NET,只需编写Web Method本身的代码,即可非常快速的创建可以实用的Web Services:  
  表3. 用.NET实现的
xml Web Services
  [WebMethod]
  public Person[] GetPersons()
  {
  Person Alice=new Person("Alice","Female");
  Person Bob=new Person("Bob","Male");
  Person Chris=new Person("Chris","Female");
  Person Dennis=new Person("Dennis","Male");  
  return new Person[];
  }  
  [WebMethod]
  public string GetPersonTable()
  {
  DataTable table=new DataTable("Person");
  table.Columns.Add("Name");
  table.Columns.Add("Gender");
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);
  table.Rows.Add(new string[2]);  
  DataSet dataset=new DataSet("PersonTable");
  dataset.Tables.Add(table);  
  System.Text.StringBuilder strbuilder=new System.Text.StringBuilder();
  StringWriter writer=new StringWriter(strbuilder);
  dataset.Write
xml(writer,System.Data.
xmlWriteMode.IgnoreSchema);  
  return strbuilder.ToString();
  }  
  在上面的代码中,函数GetPersons()和GetPersonTable()分别对应于"1. 概述"中所提到的两种解决方案。其中,Person类型就是用于封装数据集中一行数据的自定义的数据类型:  
  表4. 自定义类型Person
  [Serializable]
  public class Person
  {
  public Person()    
  public Person(string name,string gender)    
  public string Name="";
  public string Gender="";
  }