【WCF--初入江湖】10 序列化和传输大型数据流

10 序列化和传输大型数据流

1.前言

  理解WCF的序列化形式
    掌握DataContractSerializer序列化对象
    比较性能
    比较xmlSerializer序列化对象
 
  大数据量传输设置
    修改配置文件
    设置编码
           设置流模式
 
[DataContract]

    

    数据契约则是定义服务端和客户端之间要传送的自定义数据类型。
  那么该类型就可以被序列化在服务端和客户端之间传送。
  类只有声明为[DataContract],该类型的对象才可以被传送,
  且只有类的属性会被传送,需要在属性前加[DataMember]声明,这样该属性就可以被序列化传送。
[DataContract]   //数据契约声明
    class MyDataContract
    {
        [DataMember]//数据成员标记
        public string Name
        {
            get;  set;
        }
        [DataMember]//数据成员标记
        public string Email
        {
            get;   set;
        }
   }

 

2. WCF服务所支持的序列化器

  现在一共是4种:
    【1】XmlSerializer
    【2】DataContratSerializer
    【3】NetDataContractSerializer
    【4】DataContractJsonSerializer

2.1 DataContractSerializer 序列化器

    DataContractSerializer 是WCF默认的序列化器:

    【1】创建DataContractSerializer实例的方式
        指定根类型进行创建,根类型是序列化或反序列化实例的类型。
        
DataContractSerializer dcs = new DataContractSerializer(typeof(Person));

 

    【2】DataContractSerializer序列化方法
        WriteObject()  //序列化
        ReadObject()  //反序列化

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace Keasy5.WCF.DataContractSerializers
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Address { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof (Person));
            MemoryStream memoryStream = new MemoryStream();
            Person person = new Person()
            {
                Name = "ABC",
                Age = 100,
                Address = "N/A"
            };

            dataContractSerializer.WriteObject(memoryStream, person);//序列换

            memoryStream.Position = 0;
            StreamReader streamReader = new StreamReader(memoryStream);
            string temp = streamReader.ReadToEnd();

            Console.WriteLine("序列化");
            Console.WriteLine(temp);

            Console.WriteLine("序列化");
            var buffer = System.Text.Encoding.UTF8.GetBytes(temp);
            MemoryStream memoryStream2 = new MemoryStream(buffer);
            Person person2 = dataContractSerializer.ReadObject(memoryStream2) as Person; //反序列化

            Console.WriteLine("姓名:{0}-年龄:{1}-地址:{2}",person2.Name,person2.Age,person2.Address );

            Console.ReadKey();

        }
    }
}
View Code

 

3. 大数据量传输设置

  

  

  3.1 大数据量传输设置

  【1】客户端

    修改客户端接收的最大数据值。

        默认情况下,其接收的最大数据量为65535字节,如超过这个范围,就必须修改默认设置。

     <binding … maxReceivedMessageSize=“999999“>

    或

      bind.MaxReceivedMessageSize = 9999999

 

  【2】WCF服务端

      WCF没有限制服务端发送数据的大小,但可以设置

           serviceBehaviors的dataContractSerializer 的maxItemsInObjectGraph属性,

    用来指定序列化和反序列化对象的最大数目,默认值为65535。

    注意:当序列化数组时,每个数组元素当作一个对象
 
 
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <dataContractSerializer maxItemsInObjectGraph="999999"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

 

 
 

3.2 本文与二进制

      在大多数情况下,二进制消息量要少于XML本文消息。

        byte[] getFile();

 

3.3 编码

    
    编码方式,跟绑定协议有很大的关系,比如:基于Http协议 编码基本都是TextMessageEncodingBingingElement编码。
 
    【1】TextMessageEncodingBingingElement         
      文本消息编码(如:Xml格式),跟其他平台互操作强
    <bindings>
      <wsHttpBinding>
        <binding name="webHttpBinding"
                 messageEncoding="Text"></binding>
      </wsHttpBinding>
    </bindings>

 

    【2】MtomMessageEncodingBingingElement  
        对消息的部分内容进行二进制进行特殊处理,当传输的数据超过1KB时,可以考虑该编码形式。
 
      
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="webHttpBinding"
                 messageEncoding="Mtom"></binding>
      </wsHttpBinding>
    </bindings>

 

    【3】BinaryMessageEncodingBindingElement

       二进制消息编码,基本跟TCP协议有关。

3.4 流模式

    当有大量的数据要传输时,WCF中的流模式是整体缓冲和处理内存中消息的默认行为的一个可行的替代方法。

  如果数据无法分段、消息必须以及时的方式传递或者当传输启动时数据尚未完全就绪,则应考虑启用流模式,

  且只能对大型消息(带文本或二进制内容)启用流模式。

    以缓慢的形式传输,需要会话的支持

    当启用流模式后,其他一些特征可能就不能使用了,如:

      不能设置有些安全选项,无法进行可靠性会话。

<bindings>
  <basicHttpBinding>
    <binding name="" transferMode="streaming" />
  </basicHttpBinding>
</bindings>

  代码形式:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Stream RequestInfo();

 

   3.5 大数据量传输--自定义方案

      3.5.1 自定义方案

    转成二进制格式
    压缩消息内容
    切割后分块传递

 

      3.5.2 压缩组件:ICSharpCode.SharpZipLib

        链接: http://pan.baidu.com/s/1qWyPG4W 密码: 1re8

       CompressionHelper.cs

using System;
using System.IO;
using System.Text;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace CompressDataSet.Common
{
    /// <summary>
    /// 压缩强度。
    /// </summary>
    public enum CompressionLevel
    {
        /// <summary>
        /// 采用最好的压缩率。
        /// </summary>
        BestCompression,

        /// <summary>
        /// 采用默认的压缩率。
        /// </summary>
        DefaultCompression,

        /// <summary>
        /// 采用最快的压缩速度。
        /// </summary>
        BestSpeed,

        /// <summary>
        /// 不采用任何压缩。
        /// </summary>
        NoCompression
    }

    /// <summary>
    /// CompressionHelper 的摘要说明。
    /// </summary>
    public class CompressionHelper
    {
        /// <summary>
        /// 获取和设置压缩强度。
        /// </summary>
        public CompressionLevel Level;

        public CompressionHelper()
        {
            Level = CompressionLevel.DefaultCompression;
        }

        public CompressionHelper(CompressionLevel level)
        {
            Level = level;
        }

        #region Public Methods
        /// <summary>
        /// 从原始字节数组生成已压缩的字节数组。
        /// </summary>
        /// <param name="bytesToCompress">原始字节数组。</param>
        /// <returns>返回已压缩的字节数组</returns>
        public byte[] CompressToBytes(byte[] bytesToCompress)
        {
            MemoryStream ms = new MemoryStream();
            Stream s = GetOutputStream(ms);
            s.Write(bytesToCompress, 0, bytesToCompress.Length);
            s.Close();
            return ms.ToArray();
        }

        /// <summary>
        /// 从原始字符串生成已压缩的字符串。
        /// </summary>
        /// <param name="stringToCompress">原始字符串。</param>
        /// <returns>返回已压缩的字符串。</returns>
        public string CompressToString(string stringToCompress)
        {
            byte[] compressedData = CompressToBytes(stringToCompress);
            string strOut = Convert.ToBase64String(compressedData);
            return strOut;
        }

        /// <summary>
        /// 从原始字符串生成已压缩的字节数组。
        /// </summary>
        /// <param name="stringToCompress">原始字符串。</param>
        /// <returns>返回已压缩的字节数组。</returns>
        public byte[] CompressToBytes(string stringToCompress)
        {
            byte[] bytData = Encoding.Unicode.GetBytes(stringToCompress);
            return CompressToBytes(bytData);
        }

        /// <summary>
        /// 从已压缩的字符串生成原始字符串。
        /// </summary>
        /// <param name="stringToDecompress">已压缩的字符串。</param>
        /// <returns>返回原始字符串。</returns>
        public string DecompressToString(string stringToDecompress)
        {
            string outString = string.Empty;
            if (stringToDecompress == null)
            {
                throw new ArgumentNullException("stringToDecompress", "You tried to use an empty string");
            }

            try
            {
                byte[] inArr = Convert.FromBase64String(stringToDecompress.Trim());
                outString = Encoding.Unicode.GetString(DecompressToBytes(inArr));
            }
            catch (NullReferenceException nEx)
            {
                return nEx.Message;
            }

            return outString;
        }

        /// <summary>
        /// 从已压缩的字节数组生成原始字节数组。
        /// </summary>
        /// <param name="bytesToDecompress">已压缩的字节数组。</param>
        /// <returns>返回原始字节数组。</returns>
        public byte[] DecompressToBytes(byte[] bytesToDecompress)
        {
            byte[] writeData = new byte[4096];
            Stream s2 = GetInputStream(new MemoryStream(bytesToDecompress));
            MemoryStream outStream = new MemoryStream();

            while (true)
            {
                int size = s2.Read(writeData, 0, writeData.Length);
                if (size > 0)
                {
                    outStream.Write(writeData, 0, size);
                }
                else
                {
                    break;
                }
            }
            s2.Close();
            byte[] outArr = outStream.ToArray();
            outStream.Close();
            return outArr;
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// 根据压缩强度返回使用了不用压缩算法的 Deflate 对象。
        /// </summary>
        /// <param name="level">压缩强度。</param>
        /// <returns>返回使用了不用压缩算法的 Deflate 对象。</returns>
        private Deflater GetDeflater(CompressionLevel level)
        {
            switch (level)
            {
                case CompressionLevel.DefaultCompression:
                    return new Deflater(Deflater.DEFAULT_COMPRESSION);

                case CompressionLevel.BestCompression:
                    return new Deflater(Deflater.BEST_COMPRESSION);

                case CompressionLevel.BestSpeed:
                    return new Deflater(Deflater.BEST_SPEED);

                case CompressionLevel.NoCompression:
                    return new Deflater(Deflater.NO_COMPRESSION);

                default:
                    return new Deflater(Deflater.DEFAULT_COMPRESSION);
            }
        }

        /// <summary>
        /// 从给定的流生成压缩输出流。
        /// </summary>
        /// <param name="inputStream">原始流。</param>
        /// <returns>返回压缩输出流。</returns>
        private DeflaterOutputStream GetOutputStream(Stream inputStream)
        {
            return new DeflaterOutputStream(inputStream, GetDeflater(Level));
        }

        /// <summary>
        /// 从给定的流生成压缩输入流。
        /// </summary>
        /// <param name="inputStream">原始流。</param>
        /// <returns>返回压缩输入流。</returns>
        private InflaterInputStream GetInputStream(Stream inputStream)
        {
            return new InflaterInputStream(inputStream);
        }
        #endregion
    }
}
View Code

        使用时,用两个dll:

    CompressDataSet.Common.dll

    ICSharpCode.SharpZipLib.dll

        

            CompressDataSet.Common.CompressionHelper compressionHelper = new CompressionHelper();
            compressionHelper.DecompressToBytes();  //解压缩
            compressionHelper.DecompressToString(); //解压缩
            compressionHelper.CompressToString(); //压缩
            compressionHelper.CompressToBytes();  //压缩

 

 

 

      

 

 

posted @ 2014-07-05 04:48  easy5  阅读(1027)  评论(0编辑  收藏  举报