WCF传输大数据量DataSet

    这几天看了WCF相关的资料,然后就产生一个想法.如何实现WCF实现传输DataSet,这个服务的主要功能是客户端调用服务端的一个函数,这个函数接受一个DataSet的参数,然后再返回一个DataSet,当然这个功能很简单,几行代码就搞定了.可是当如果DataSet内的数据量非常大的时候,那就麻烦了.(暂不讨论传输大数据量的DataSet是否合理),WCF默认最大传输数据量为64K,当然可以实现修改配置文件来传输大数据量,可是不能解决本质的问题,我目前解决这个问题的方式是,把一个DataSet序列化为一个字节,然后把这些字节进行压缩,然后每次发送一小段字节回去,接受到这个些字节以后然后在解压缩,再反序列化为为DataSet,这样就实现了,传入一个DataSet然后再返回一个DataSet,这样的话,就需要用到WCF的双向通信,使用回调函数


             DuplexChannelFactory<IHello> channelFactory = new DuplexChannelFactory<IHello>(new InstanceContext(new ClientCallBack()), "defaultEndpoint");
            IHello getHello 
= channelFactory.CreateChannel();
                
//传入DataSet到服务端
                getHello.SayHelloTo();

首先客户端调用服务端的函数SayHelloTo(),
    public void SayHelloTo()
        {
            
//读取客户端传入的DataSet
            #region 服务端的数据
            ICallback callback 
= OperationContext.Current.GetCallbackChannel<ICallback>();
 
            
int intNum = callback.getTimes() + 1//获取读取字节流的次数
            MemoryStream Mstream = new MemoryStream();
            
byte[] getbyte;
            
for (int i = 1; i < intNum; i++)
            {
                getbyte 
= callback.getBytes(i);
                Mstream.Write(getbyte,
0,getbyte.Length);//写到内存中
           }
            Mstream.Position 
= 0;
            getbyte 
= new byte[Mstream.Length];
            Mstream.Read(getbyte, 
0, getbyte.Length);//从内存中读到getbyte中
            Mstream.Close();

            
//反序列化
            ServiceData = KCDataFormatter.RetrieveDataSetDecompress(getbyte);
            
//----------------------------
            
//此处得到序列化以后的字节,可以再反序列化为DataSet,得到DataSet就可以对个DataSet做处理,删除,修改,
            
//处理完成再把处理完成的DataSet赋值给ServiceData,就可以了
            
//----------------------------
            #endregion
        }
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
此时就会调用客户端的回调函数
    public class ClientCallBack : ICallback
    {
        
#region ICallBack 成员
        
//要上传的数据
        public void getData()
        {
            DataSet ds 
= new DataSet("test");
            DataTable table 
= new DataTable("test");
            DataColumn column 
= new DataColumn("test");
            column.DataType 
= Type.GetType("System.String");
            table.Columns.Add(column);
            DataRow row;
            
for (int i = 0; i < 200000; i++)
            {
                row 
= table.NewRow();
                row[
"test"= "Hello";
                table.Rows.Add(row);
            }
            ds.Tables.Add(table);
            byte_All 
= KCDataFormatter.GetBinaryFormatDataCompress(ds);
        }
        
private int i = 1000//每次读取字节的数量
        byte[] byte_All;//获取要上传的字节流
        MemoryStream Mstream;//
        public byte[] getBytes(int intNum)
        {
            
int j = 1000;
            
byte[] buffer;
            
if (intNum < iti)  //判断是否是最后一次循环
            {
                buffer 
= new byte[1000];
            }
            
else
            {

                
int nn = byte_All.Length - ((iti - 1* 1000);
                buffer 
= new byte[nn];
                j 
= nn;
            }
            
int iold = (i * (intNum - 1));  //记录上一次的字节位置
            Mstream = new MemoryStream();
            Mstream.Write(byte_All, iold, j);
//从byte_All中的第iolld开始写入j(最多不超过)个到内存中
            buffer = Mstream.ToArray();
            Mstream.Close();
            Mstream.Dispose();
            
return buffer;
        }
        
private int iti = 0;  //初始化循环次数
        public int getTimes()  //将数据流分为多少部分
        {
            getData();
            
int temp = byte_All.Length / 1000;
            
int intNum = byte_All.Length % 1000 != 0 ? temp + 1 : temp;
            iti 
= intNum;
            
return intNum;
        }
        
#endregion
    }

getData()函数内可以编写需要上传的DataSet,我这里是生成20W条记录.通过回调函数就会把这20W条数据传入服务端,回调结束了,DataSet也就传入了服务端了.(我这里服务端没有任何处理这个DataSet就直接返回这个DataSet会客户端),客户端继续执行他的逻辑,此时的逻辑是把刚才传入的服务端的Dataset再返回给客户端
     //获取服务端返回的DataSet
                int intNum = getHello.serviceTime() + 1//获取读取字节流的次数
                MemoryStream Mstream = new MemoryStream();
                
byte[] getbyte;
                
for (int i = 1; i < intNum; i++)
                {
                    getbyte 
= getHello.DownByte(i);
                    Mstream.Write(getbyte, 
0, getbyte.Length);//写到内存中
                }
                Mstream.Position 
= 0;

                getbyte 
= new byte[Mstream.Length];
                Mstream.Read(getbyte, 
0, getbyte.Length);//从内存中读到getbyte中
                Mstream.Close();

                
//反序列化
                DataSet ds = KCDataFormatter.RetrieveDataSetDecompress(getbyte);
这里就得到了服务端返回的DataSet.
全部代码已经打包,vs2008中文版编译通过!

如果谁还能提供更好的方法希望能公布出来,让大家共享!我也想知道一下哦.!
我也是WCF的一个初学者!
 下载
目前我还有问题没有解决
就是实现使用IIS来公布这个服务(就是Http),现在是使用netTcpBinding协议,我在使用WSDualHttpBinding协议的时候配置老是失败,如果谁能配置成功,希望能发一份代码给我,还有就是如何把它封装成一个通用的方法来使用!否则以后每次这样通讯都要写如此多代码很麻烦!
(问题已经决了)
posted @ 2008-05-27 11:03  索马  阅读(10289)  评论(21编辑  收藏  举报