这次我们来做一个例子,流程很简单:客户端向服务器发送一条指令,服务端接收到这条指令之后,向客户端发送数据库中查询到的数据,最终显示在DataGridView上。
根据上一篇文章介绍的Slice语法,我们先来定义ICE文件。我定义两个ICE文件,一个用来描述测试数据库表中属性相关信息,另一个则是请求数据的方法。
结构如下:
定义结构体,和数据库中表的列对应,添加序列(相当于数组类型)。
在获取表的方法中注意要记得#include带有结构的ice文件,并把接口函数的返回值类型写成之前定义的数组类型,否则就像HelloWorld例子中只能在服务器显示,调回不到客户端了。(DbTableDataSeq getDataFromDb(string requestCode);这个方法其实就是客户端一调用,然后服务器操作完成,最后返回DbTableDataSeq类型的数据)
编译ICE文件:
在数据库中随便插入几条数据:
之后是一系列基本工作:创建工程,添加对ICE的引用,拖入编译好的文件,对具有接口函数的ICE文件创建实现类,实现抽象类DoSelectTableDisp_
大体结构如下图:
为了结构能更清晰,我们把它改成这样,同时添加上查询数据库的方法:
给出这几个类的代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace ConsoleSer.common 7 { 8 public class DbData 9 { 10 public string dataName;//数据库中列名 11 public object dataValue;//数据库中列值 12 } 13 14 public class DbDataList 15 { 16 public IList<DbData> dataRow; 17 } 18 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using ConsoleSer.common; 6 using IBM.Data.DB2; 7 using System.Data; 8 9 namespace ConsoleSer.database 10 { 11 public class Db2:DbMain 12 { 13 public override IList<DbDataList> GetDataFromDatabase(string strSql) 14 { 15 IList<DbDataList> list = new List<DbDataList>(); 16 17 using (DB2Connection con = new DB2Connection("server=127.0.0.1;database=TEST;uid=db2admin;pwd=db2admin;")) 18 { 19 con.Open(); 20 DB2DataAdapter oda = new DB2DataAdapter(strSql, con); 21 DataSet ds = new DataSet(); 22 oda.Fill(ds); 23 if (ds.Tables.Count > 0) 24 { 25 DataTable dt = ds.Tables[0]; 26 for (int i = 0; i < dt.Rows.Count; i++) 27 { 28 IList<DbData> rowsData = new List<DbData>(); 29 for (int j = 0; j < dt.Columns.Count; j++) 30 { 31 DbData data = new DbData(); 32 data.dataName = dt.Columns[j].ColumnName; 33 data.dataValue = dt.Rows[i][data.dataName]; 34 rowsData.Add(data); 35 } 36 DbDataList rows = new DbDataList(); 37 rows.dataRow = rowsData; 38 list.Add(rows); 39 } 40 } 41 } 42 return list; 43 } 44 } 45 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using ConsoleSer.common; 6 7 namespace ConsoleSer.database 8 { 9 public class DbMain 10 { 11 public virtual IList<DbDataList> GetDataFromDatabase(string strSql) 12 { 13 IList<DbDataList> list = new List<DbDataList>(); 14 return list; 15 } 16 } 17 }
最终查询完数据库返回的是这样的一条数据:(IList<DbDataList> list = new List<DbDataList>(); DbDataList包含两个字段string dataName;object dataValue;)
但是这并不是我们想要的返回类型,我们再将其转换为DbTableData类型数组,于是在TestTableMethodI实现类中有如下代码(假设客户端请求字符串是getTable):
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using tableStructFamily; 6 using ConsoleSer.common; 7 using ConsoleSer.database; 8 9 namespace ConsoleSer.slice2csI 10 { 11 class TestTableMethodI:DoSelectTableDisp_ 12 { 13 public static List<DbTableData> tbData = new List<DbTableData>();//数据库中表信息 14 private static DbMain dbObject = new Db2(); 15 16 public override DbTableData[] getDataFromDb(string requestCode, Ice.Current current__) 17 { 18 if (requestCode == "getTable") 19 { 20 Console.WriteLine("收到请求!"); 21 return selectDataFromDb(); 22 } 23 else 24 { 25 throw new Exception(); 26 } 27 } 28 29 private DbTableData[] selectDataFromDb() 30 { 31 IList<DbDataList> list = dbObject.GetDataFromDatabase("select * from A.T_test"); 32 33 DbTableData[] objs = new DbTableData[list.Count]; 34 35 for (int i = 0; i < list.Count; i++) 36 { 37 DbDataList row = list[i]; 38 DbTableData obj = GetTableObj(row); 39 tbData.Add(obj); 40 objs[i] = obj; 41 } 42 return objs; 43 } 44 45 private DbTableData GetTableObj(DbDataList dataRow) 46 { 47 DbTableData obj = new DbTableData(); 48 for (int i = 0; i < dataRow.dataRow.Count; i++) 49 { 50 DbData data = dataRow.dataRow[i]; 51 setObjValue(data, ref obj); 52 } 53 return obj; 54 } 55 56 private void setObjValue(DbData data, ref DbTableData obj) 57 { 58 string name = data.dataName.ToLower(); 59 switch (name) 60 { 61 case "id": 62 obj.ID = Convert.ToInt32(data.dataValue); 63 break; 64 case "nname": 65 obj.Nname = data.dataValue.ToString(); 66 break; 67 default: 68 break; 69 } 70 } 71 } 72 }
附上Main函数初始化ICE的方法:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using tableStructFamily; 6 7 namespace ConsoleTestIceServer 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 int status = 0; 14 Ice.Communicator ic = null; 15 try 16 { 17 ic = Ice.Util.initialize(ref args); 18 Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints("tableSelector", "default -p 10000"); 19 Ice.Object obj = new ConsoleSer.slice2csI.TestTableMethodI(); 20 adapter.add(obj, Ice.Util.stringToIdentity("tableSelector")); 21 adapter.activate(); 22 Console.WriteLine("初始化成功!"); 23 ic.waitForShutdown(); 24 } 25 catch (Exception e) 26 { 27 Console.Error.WriteLine(e); 28 status = 1; 29 } 30 finally 31 { 32 if (ic != null) 33 { 34 ic.destroy(); 35 } 36 } 37 Environment.Exit(status); 38 } 39 } 40 }
如此一来服务端代码就写好了。
很少用BD2数据库,一直用SqlServer编译时报了如下警告,不能运行:
在网上搜索了一下:改成了.NET Framwork4,没有后面的Client Profile,就可以用了;这个修改需要右击项目,然后选择其中的属性。
接下来我们编写客户端代码:
与服务端相同一开始是一系列基本工作:创建工程,添加对ICE的引用,拖入编译好的文件
大体结构如下图:
在Form上添加三个控件:
给出完整客户端代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using tableStructFamily; 10 11 namespace FormCli 12 { 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 } 19 20 private void btnSendRequestCode_Click(object sender, EventArgs e) 21 { 22 int status = 0; 23 Ice.Communicator ic = null; 24 try 25 { 26 ic = Ice.Util.initialize(); 27 txtShowMsg.AppendText("初始化成功!\r\n"); 28 Ice.ObjectPrx obj = ic.stringToProxy("tableSelector:default -p 10000"); 29 DoSelectTablePrx selector = DoSelectTablePrxHelper.checkedCast(obj); 30 if (selector == null) 31 { 32 throw new ApplicationException("Invalid proxy"); 33 } 34 txtShowMsg.AppendText("开始发送请求!\r\n"); 35 DbTableData[] objs = selector.GetDataFromDb("getTable"); 36 txtShowMsg.AppendText("发送请求成功!\r\n"); 37 38 if (objs.Length > 0) 39 { 40 txtShowMsg.AppendText("成功获取数据!\r\n"); 41 } 42 43 44 foreach (DbTableData td in objs) 45 { 46 txtShowMsg.AppendText(td.id.ToString() + "\r\n"); 47 txtShowMsg.AppendText(td.nName.ToString() + "\r\n"); 48 } 49 50 DataTable dt = new DataTable(); 51 dt.Columns.Add("ID"); 52 dt.Columns.Add("Nname"); 53 foreach (DbTableData td in objs) 54 { 55 DataRow dr = dt.NewRow(); 56 dr["ID"] = td.id; 57 dr["Nname"] = td.nName; 58 dt.Rows.Add(dr); 59 } 60 61 dgvShowTable.DataSource = dt; 62 63 //显示到gridview中 64 } 65 catch (Exception ex) 66 { 67 MessageBox.Show(ex.ToString()); 68 status = 1; 69 } 70 finally 71 { 72 if (ic != null) 73 ic.destroy(); 74 } 75 txtShowMsg.AppendText(status.ToString()); 76 //Environment.Exit(status); 77 } 78 79 } 80 }
DoSelectTablePrx selector = DoSelectTablePrxHelper.checkedCast(obj);
DbTableData[] objs = selector.GetDataFromDb("getTable");
这两行代码是客户端能获取服务器上数据的关键,客户端与服务器调用相同的函数,通过返回值类型,客户端就能够从服务器上得到返回的数据。
最终运行结果如下: