为了优化WebService传输大数据量DataSet的性能,搜索各大网站资料,尤其是参考了台湾msdn网站的一篇文章,得到一个方案,但是遇到如下问题:
WebService端代码:
[WebMethod]
public Byte[] GetDsBytes()
{
DataSet ds = new DataSet();
//这里循环将20列,10000行记录表加入到DataSet中 DataSetSurrogate sds = new DataSetSurrogate(ds); //DataSetSurrogate这个是微软官方提供的一个压缩DataSet的类库
MemoryStream s = new MemoryStream();
s.Position = 0;
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(s,sds); byte[] e = s.ToArray();

//这里测试过,直接反序列化成DataSet是成功的。 s.Close(); return e; //返回二进制序列化过的DataSet byte[]
}
客户端Winform代码:
private xxxx ws = xxxx...//实例化WebService

private void button2_Click(object sender, System.EventArgs e)
{
Byte [] bb = this.ws.GetDsBytes(); MemoryStream br = new MemoryStream(bb);
br.Position = 0;

BinaryFormatter bf = new BinaryFormatter();
object o = bf.Deserialize(br);//这里反序列化出错,错误信息如下,其中WebService1是WebService的命名空间
//未处理的“System.Runtime.Serialization.SerializationException”类型的异常出现在 mscorlib.dll 中。
//其他信息: 无法找到程序集 WebService1, Version=1.0.2227.16697, Culture=neutral, PublicKeyToken=null。 DataSetSurrogate sds = (DataSetSurrogate)o;
DataSet ds = sds.ConvertToDataSet();  br.Close(); this.dataGrid1.DataSource = ds;
}查了很多资料,csdn也有很多人问这个问题,但是都没有答案,好像是将命名空间名和类名也都序列化到二进制数组中,反序列化的时候无法对应起来,而且我客户端重新建立了一个和WebService命名空间和类库名称相同的类来接收二进制数组,再反序列化也报同样的错。期待高人出现帮忙解答,谢了!!!!!!

解决方案 »

  1.   

    object o = bf.Deserialize(br);
    -->
    object[] o = (object[])bf.Deserialize(br);
    //然后
    for (int i=0; i<o.Length; i++)
    {
      if (o[i]!=null && o[i] is DataSetSurrogate)
      {
         o[i] = ((DataSetSurrogate)o[i]).ConvertToDataSet();
      }
    }
      

  2.   

    我也做过这个测试,我的可以用呀!只是返回速度并不是很理想!
    如下我的代码,不知是否对你有用!
    [WebMethod(Description="获取业务资料远程DATASET")]
    public byte[] SurrogateRead1()
    {

                            oracleconnxxj.Open();
    xxjclxxds.SelectCommand.ExecuteNonQuery();
    xxjclxxds.Fill(dataSet11,"VEHICLE");
    sds = new DataSetSurrogate(dataSet11); 
    MemoryStream s= new MemoryStream();
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(s,sds);     
    byte[] e = s.ToArray();
    oracleconnxxj.Close();
    return e; 
      
    }客户端调用                        byte [] bb=dsclxx.SurrogateRead1();
    MemoryStream br=new MemoryStream(bb);
    BinaryFormatter bf=new BinaryFormatter();
    object o=bf.Deserialize(br);
    sds = (DataSetSurrogate) o;
    dataSet1 = sds.ConvertToDataSet(); 
    dataGrid1.DataSource=dataSet1.Tables[0];
    br.Close();
      

  3.   

    我给你两个方法,你改变一下调用,然后测试看看:
    /// <summary>
    /// 二进制序列化
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeBinary(object[] obj)
    {
    if(obj == null || obj.Length ==0)
    return new byte[]{} ;            for (int i=0; i<obj.Length; i++)
                {
                    if (obj[i]!=null && obj[i] is DataSet)
                    {
                        obj[i] = new DataSetSurrogate((DataSet)obj[i]);
                    }
                } BinaryFormatter se =new BinaryFormatter();
    MemoryStream memStream = new MemoryStream();
    se.Serialize(memStream, obj);
    byte[] bobj = memStream.ToArray();
    memStream.Close();
    return bobj;
    }
    /// <summary>
    /// 二进制反序列化
    /// </summary>
    /// <param name="bobj"></param>
    /// <returns></returns>
    public static object[] DeserializeBinary(byte[] bobj)
    {
    if(bobj==null || bobj.Length == 0)
    return new object[]{} ; MemoryStream memStream = new MemoryStream(bobj);
    memStream.Position = 0;
    BinaryFormatter de =new BinaryFormatter();
    object[] newobj = null;
    newobj =(object[])de.Deserialize(memStream);
    memStream.Close();            for (int i=0; i<newobj.Length; i++)
                {
                    if (newobj[i]!=null && newobj[i] is DataSetSurrogate)
                    {
                        newobj[i] = ((DataSetSurrogate)newobj[i]).ConvertToDataSet();
                    }
                } return newobj;
    }
      

  4.   

    lovvver(春晖) ,实际上我的那个客户端button事件里执行的代码去掉datagrid1呈现,放到webservice上执行是能反序列化成dataset的,就是放到客户端,调用webservice以后,反序列化就失败了
      

  5.   

    在客户端有没有通过WebService取出byte[]?
    如果有,那就是在客户端,将byte[]反序列化成DataSet就会出错,是吗?我认为,这还是与反序列化部分相关。
      

  6.   

    DataSetSurrogate不行,就算通过也很慢地,我用了好多压缩组件,现在还没解决问题
      

  7.   

    通过ws传递byte[]数组最好现在服务器端把byte[]转为base64字符串传出,
    客户端接受base64字符串再把它转为byte[]
      

  8.   

    to  lovvver(春晖) 从ws上穿byte[]过来是成功的,有长度,到了反序列化那行就不行了,好像和webservice上byte[]所处的对象名及命名空间名有关,但是不知道怎么解决。to  hdt(倦怠)
    把byte[]转为base64的代码如何实现?没搞过,帮助上也没搜到。谢谢了。
      

  9.   

    string str = System.Convert.ToBase64String( byte[] );
    byte[] b = System.Convert.FromBase64String( str );
      

  10.   

    webservice改成
    return System.Convert.ToBase64String( e );
    客户端接收改成
    byte [] bb = System.Convert.FromBase64String(this.ws.GetDsBytes());
    还是报老错误-_-!!!
      

  11.   

    object o = bf.Deserialize(br);//这里反序列化出错,错误信息如下,其中WebService1是WebService的命名空间
    //未处理的“System.Runtime.Serialization.SerializationException”类型的异常出现在 mscorlib.dll 中。
    //其他信息: 无法找到程序集 WebService1, Version=1.0.2227.16697, Culture=neutral, PublicKeyToken=null。
      

  12.   

    http://community.csdn.net/Expert/topic/4213/4213642.xml?temp=.9504663和上面这位老兄问题的错误是一样的。
      

  13.   

    我是参考
    http://flyskywlh.cnblogs.com/archive/2005/08/18/217382.aspx
    文章实现的。其中DataSetSurrogate类在
    http://www.microsoft.com/taiwan/msdn/columns/adonet/AdoNet_20041231.htm
    的demo下载文件里。而且button事件里的反序列化代码在webservice里另外写一个方法反序列化是可以的,放到winform里引用webservice后就出现找不到程序集的错误。
      

  14.   

    http://ahfu126.dvip51.xyuu.com/download/DataSet.rar可以下载我的代码试试
    不但使用了DataSetSurregate,还使用了GZIP进行压缩,压缩后的数据一般不到以前的10%,效率非常高!
      

  15.   

    谢谢ah__fu(阿福)兄弟,我看了你的代码,你的环境和我的环境不一样,前面我也说过,我的反序列化代码和序列化代码同在webservice一端的时候是正常执行的,但是反序列化代码放到winform客户端,由客户端引用webservice,然后再通过webservice获得byte[]后,反序列化的时候报错。我可以肯定反序列化代码的逻辑上没有问题,只不过其他一些细节比如说运行环境配置上的细节被忽略了导致反序列化失败。由于初次接触序列化反序列化,对其中的机理我还没有搞清楚,查网上资料有的人说,序列化过程中将对象所在的命名空间,类名等内容也序列化到里面了,所以导致反序列化的时候无法对本地不存在的命名空间下的对象进行反序列化,不知道是不是这个原因。
      

  16.   

    看看wsdl的定义,是否有问题。
      

  17.   

    我还奇怪 sailhzr(sailhzr) 的回复,他的环境和运行合成和我的一样的,但是他能成功,我反复重建项目好多次了,还是报错:(
      

  18.   

    改错别字:
    我还奇怪 sailhzr(sailhzr) 的回复,他的环境和运行过程和我的是一样的,但是他能成功,我反复重建项目好多次了,还是报错:(
      

  19.   

    说错了 ,是dataset在精简架构中有问题。建议构造成数据对象的数组,然后再序列化,我以前就是这样做的。对象中不能包含list,collection之类东东。
    至于提高性能,你可以用任何压缩解压方法,不菲的DataSetSurrogate。就用winzip提供的非托管代码或干脆lzw也会压缩的很好。
    不过现在的移动设备都比较厉害的,比如11M的802.11b,传你这个纪录集顶多不过2000K/100k=20秒。倒是解压的话可能也要10秒的数量级。应该要权衡一下 压缩比、传输和解压速度。
      

  20.   

    另外,如果传输过程的等待实在客户无法接受的话,还可以考虑:
    1。异步调用webservice
    2。少量多次传纪录,动态显示
      

  21.   

    谢谢天外非仙,不过问题还是没有解决我采用压缩dataset不是为了传送超大数据量的数据,只是为了将一些业务字典数据,1万条左右的进行压缩提高一下传输速度,业务字典里的数据是需要全部拿来使用的,不是为了做显示的,所以一定要全部传过来。
      

  22.   

    我在写串行化程序的时候也遇到过这样的问题,串行化和反串行化不是一个程序中好像就出这种问题,把串行化的程序和反串行化的放在一起,就可以正常工作,即就是反串行化的程序中用到的是同样的Class,是不是串行化时保存原串行化程序的版本信息阿。是不是要把串行化的Class编译成单独的模块阿。
      

  23.   

    //DataSetSurrogate这个是微软官方提供的一个压缩DataSet的类库//未处理的“System.Runtime.Serialization.SerializationException”类型的异常出现在 mscorlib.dll 中。
    //其他信息: 无法找到程序集 WebService1, Version=1.0.2227.16697, Culture=neutral, PublicKeyToken=null。在精简架构中的DataSetSurrogate要重新编译才行;
    或者DataSetSurrogate中本身就存在精简架构不支持的序列化方法。
    这是dotnet1.1的问题,
    我以前建议的主要内容是要避开DataSet方法,传输过程中采用对象数组或自定义的压缩数据对象。
    总之,精简架构是问题的根源,DataSetSurrogate到底是否可以在精简架构中使用,必须有它的原代码才能考证。另外,"mscorlib.dll",CE4.0与精简架构的兼容问题也是有的。
    在以前的一个项目中,我考虑以上诸多因素,最终放弃了DataSet方法,采用对象数组。
    只是建议,期待高人查出其中原因。
      

  24.   

    不知道天外小仙说的精简构架是不是指得compact那个版本,我用的是是26M多得那个framework包,好像不是compact的版本,应该是完全版吧
      

  25.   

    问题解决啦,待会放出答案,木哈哈哈,感谢天外小仙给我了一个提示,最终测试结果是:未采用DataSetSurrogate+二进制序列化的事件一般是3s多点,反复调用结果差不多采用了的结果是第一次调用1s多点,以后的每次调用都是0。7~0。8s左右,效果还是挺明显的下一步考虑用sharpziplib压缩看看效果,据说效果不错,不过不知道压缩起来系统资源占用如何,我想会比DataSetSurrogate这种类库来压缩占用cpu多些吧。
      

  26.   

    我就是前段时间做的测试,我是测试成功了!
    是否你的DLL有问题!如有需要,就加
      

  27.   

    上句没打完!
    就是前段时间做的测试,我是测试成功了!
    是否你的DLL有问题!如有需要,我发一个给你!
      

  28.   

    天外小仙云:
    ------------
    另外,"mscorlib.dll",CE4.0与精简架构的兼容问题也是有的。
    ------------让我考虑到的就是DataSetSurrogate的版本兼容问题会不会导致反序列化失败,其实是我犯了一个低级错误,就是我不是引用同一个DataSetSurrogate.dll来实现序列化反序列化,而是将DataSetSurrogate.cs直接放到服务器端和客户端的项目代码中,这样导致了2个DataSetSurrogate分别采用服务器端版本和客户端版本而导致版本不一致,反序列化失败,而将DataSetSurrogate分离出来单独做了一个类库项目,服务器端和客户端引用,就保持了一致,反序列化成功。至此问题解决。还有一点没搞明白就是,实际上反序列化的时候还没使用DataSetSurrogate类库功能,为什么反序列化直接就失败了呢object o = bf.Deserialize(br);//这里失败,程序中断DataSetSurrogate sds = (DataSetSurrogate)o;//这行才开始真正调用DataSetSurrogate类库将对象类型进行转换。序列化的机制还是没搞明白,唉,继续研究吧。结贴了,谢谢各位帮忙!!!