【轉:】
1. 概述
很多正在開發或者打算開發XML Web Services的程式員都問過這樣的一個問題:"我的WebService返回的結果是一個DataSet類型的對象,但如果我的用戶端不是用.NET寫的(因而沒有內建的DataSet類型),那該如何調用這個WebService並訪問DataSet中的資料呢?"。
對於這個問題,首先應該說的是:1)在多種語言共存的編程環境下,是不適合使用類似DataSet這種只屬於特定語言的資料類型的。不管是在XMLWebServices還是CORBA的環境中,都應該盡量使用單一資料型別以及單一資料型別的數組。2)應當很謹慎的決定是否需要通過WebService來返回大量資料。由於網路傳輸的開銷既包括HTTP串連建立的時間,也包括傳送資料的時間,因此需要在減少訪問伺服器次數和減少網路傳輸量之間尋找一個合適的平衡。如非必須,則不適合通過WebService傳送含有幾十條或者幾百條資料的資料表。
然後,就問題本身而言,.NET WebServices返回的DataSet類型是可以直接被其他非.NET的用戶端解析的,因為即便是DataSet類型的傳回值,也會被表達成XML格式再進行傳輸。下面的例子就是一個傳回型別為DataSet的WebMethod,及其被調用後返回的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]{"Alice","Female"});
table.Rows.Add(new string[2]{"Bob","Male"});
table.Rows.Add(new string[2]{"Chris","Male"});
DataSet dataset=new DataSet("PersonTable");
dataset.Tables.Add(table);
return dataset;
}
表2. 被格式化成XML的DataSet
<?xml version="1.0"encoding="utf-8"?>
<DataSetxmlns="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:choicemaxOccurs="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:diffgramxmlns: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.WriteXML()方法將資料集中的資料提取成XML格式,並以字串的形式返回給用戶端,再由用戶端解析XML字串,還原出資料。由於使用WriteXML()的時候能夠過濾掉冗餘資訊,返回的內容和圖表2中的內容相比大大簡化了。
2. 建立.NET Web Services,返回資料集合
藉助於Visual Studio.NET,只需編寫Web Method本身的代碼,即可非常快速的建立可以實用的WebServices:
表3. 用.NET實現的XML Web Services
[WebMethod]
public Person[] GetPersons()
{
Person Alice=newPerson("Alice","Female");
Person Bob=newPerson("Bob","Male");
Person Chris=newPerson("Chris","Female");
Person Dennis=newPerson("Dennis","Male");
return newPerson[]{Alice,Bob,Chris,Dennis};
}
[WebMethod]
public string GetPersonTable()
{
DataTabletable=new DataTable("Person");
table.Columns.Add("Name");
table.Columns.Add("Gender");
table.Rows.Add(new string[2]{"Alice","Female"});
table.Rows.Add(new string[2]{"Bob","Male"});
table.Rows.Add(new string[2]{"Chris","Female"});
table.Rows.Add(new string[2]{"Dennis","Male"});
table.Rows.Add(newstring[2]{"Eric","Male"});
DataSetdataset=new DataSet("PersonTable");
dataset.Tables.Add(table);
System.Text.StringBuilderstrbuilder=new System.Text.StringBuilder();
StringWriter writer=new StringWriter(strbuilder);
dataset.WriteXml(writer,System.Data.XmlWriteMode.IgnoreSchema);
returnstrbuilder.ToString();
}
在上面的代碼中,函數GetPersons()和GetPersonTable()分別對應於"1.概述"中所提到的兩種解決方案。其中,Person類型就是用於封裝資料集中一行資料的自訂的資料類型:
表4. 自訂類型Person
[Serializable]
public class Person
{
public Person()
{
}
public Person(stringname,string gender)
{
this.Name=name;
this.Gender=gender;
}
public string Name="";
public stringGender="";
}