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