Delphi調用.NET的WebService
問題的來源請參考gattaca的留言,雖然問題狠簡單,但是對於不熟悉ClientaDataSet的人來說,還是值得研究的。本例將實現一個基於.NET的WebService,並且使用Delphi調用,獲取數據。
首先開發一個WebService,我使用VS2008下C#語言進行開發,新建一個ASP.NET Web Service工程,代碼如下:
[WebMethod]
public string GetData() {
string ConnStr = "Provider=SQLOLEDB.1;Password=\"\";Persist Security Info=True;User ID=sa;Initial Catalog=Northwind;Data Source=192.168.1.100";
OleDbConnection myConnection = new OleDbConnection(ConnStr);
string strSQL = "select * from Employees";
OleDbDataAdapter myAdapter = new OleDbDataAdapter(strSQL, myConnection);
DataSet ds = new DataSet();
myAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
myAdapter.Fill(ds, "Employees");
return CSDS2DDS.ToClientDataSet(ds, "Employees");
}
其中CSDS2DDS是CSharpDataSetToDelphiDataSet的縮寫,它包含一個靜態方法,用於將.NET的數據集轉換為ClientDataSet所使用的XML。這個類的代碼如下:
public class CSDS2DDS {
public CSDS2DDS() {
}
public static string ToClientDataSet(DataSet ds, string TableName) {
int FieldCount = ds.Tables[TableName].Columns.Count;
string result = "<?xml version=\"1.0\" standalone=\"yes\"?>";
result += "<DATAPACKET Version=\"2.0\">";
result += "<METADATA><FIELDS>";
for (int i = 0; i < FieldCount; i++) {
DataColumn dc = ds.Tables[TableName].Columns[i];
string FieldType = dc.DataType.Name.ToLower();
// integer
if (FieldType.ToLower() == "int32")
FieldType = "i4";
// int64
if (FieldType.ToLower() == "int64")
FieldType = "i8";
// float
if (FieldType.ToLower() == "single")
FieldType = "r8";
// memo
if (FieldType.ToLower() == "string" && dc.MaxLength > 255)
FieldType = "bin.hex";
// bytes
if (FieldType.ToLower() == "byte[]")
FieldType = "bin.hex";
result += string.Format("<FIELD attrname=\"{0}\" fieldtype=\"{1}\" ", dc.ColumnName, FieldType);
if (FieldType == "bin.hex" && dc.DataType.Name.ToLower() == "string")
result += "SUBTYPE=\"Text\" ";
else if (FieldType == "string")
result += string.Format("WIDTH=\"{0}\" ", dc.MaxLength);
else if (FieldType == "sqldatetime")
result += "SUBTYPE=\"Formatted\"";
else if (FieldType == "bin.hex" && dc.DataType.Name.ToLower() != "string" || dc.DataType.Name.ToLower() == "byte[]")
result += "SUBTYPE=\"Binary\"";
result += "/>";
}
result += "</FIELDS><PARAMS/></METADATA>";
result += "<ROWDATA>";
int RowCount = ds.Tables[TableName].Rows.Count;
for (int i = 0; i < RowCount; i++) {
result += "<ROW RowState=\"4\" ";
for (int j = 0; j < FieldCount; j++) {
DataTable dt = ds.Tables[TableName];
string value = dt.Rows[i].ItemArray[j].ToString();
value = value.Replace("\"", """);
result += string.Format("{0}=\"{1}\" ",
dt.Columns[j].ColumnName,
value);
}
result += "/>";
}
result += "</ROWDATA></DATAPACKET>";
return result;
}
}
這個類非常明確,就是用循環的方式讀出.NET數據集中的數據,並且拼裝成ClientDataSet使用的XML
做完這一步,就可以將WebService部署去IIS,然後用Delphi直接調用了,用WSDL Importer或RO引入WSDL,生成單元後就可以調用它。
procedure TForm1.FormCreate(Sender: TObject);
var
xml: string;
begin
xml := Service.GetServiceSoap.GetData;
ClientDataSet1.XMLData := xml;
ClientDataSet1.Open;
end;
程序執行後即可看到,數據從.NET端傳遞到了Delphi端。
由於轉換的代碼直接讀取.NET的數據集,因此對delphi端沒有任何影響。
如果以後.NET的數據集發生了改變,也只需要在服務器上直接修改轉換代碼,.NET數據集的格式改變的可能性非常小。至少從.NET1.1開始,到現在的.NET3.5,它完全沒有改變過。
注意:部署WebService時請使用IIS6.0,盡量使用Windows2003,如果用XP,可能會產生不可預知的問題。