首页 > 代码库 > WCF传输1-你是否使用过压缩或Json序列化?

WCF传输1-你是否使用过压缩或Json序列化?

1.当遇到需要传输大量数据时,怎么样传输数据?

2.压缩数据有哪几种常见的方式?

 

问题1解答:通过压缩来传输数据

问题2解答:

            (1)WCF自带的压缩方式

            (2)自定义WCF binding进行压缩

            (3)将对象序列化为JSON格式

 

今天来探讨一下WCF自带的压缩方式Gzip和Json序列化

 

我的其他WCF文章:

WCF安全1-开篇

WCF安全2-非对称加密

WCF安全3-Transport与Message安全模式

WCF传输1-你是否使用过压缩或Json序列化?

 

 

先上图:

技术分享

 

1.WCF自带的压缩方式进行压缩数据及传输数据

参考资料:https://msdn.microsoft.com/en-us/library/system.servicemodel.channels.compressionformat.aspx

总共有三种方式:
     Deflate:The Deflate compression format.
     GZip:The GZip compression format.
     None: The none compression format.

注意,.NET framwork版本需要在4.0以上(包含4.0)。

1.1 Code的实现:

(1)Server端和Client的配置

<binarymessageencoding compressionformat="GZip">

    <bindings>      <customBinding>        <binding name="BindingForTcp" receiveTimeout="00:05:00" sendTimeout="00:05:00">            <binaryMessageEncoding compressionFormat="GZip">              <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" />            </binaryMessageEncoding>            <httpTransport maxReceivedMessageSize="2147483647">                          </httpTransport>          </binding>        </customBinding>    </bindings>
<services>      <service name="Jackson0714.WcfServices.Service.GetPersonDetailService"               behaviorConfiguration="metadataBehavior" >        <endpoint address="http://127.0.0.1:3725/GetPersonDetailService"                  binding="customBinding"                   bindingConfiguration ="BindingForTcp"                  contract="Jackson0714.WcfServices.Service.Interface.IGetPersonDetailService" />      </service></services>

注意:Client和Server端必须使用相同的binding。 

(2)Server端代码

打开端口,host服务

using System;using System.ServiceModel;using Jackson0714.WcfServices.Service;namespace Jackson0714.WcfServices.Hosting{    class Program    {        static void Main(string[] args)        {            ServiceHost getPersonDetailServiceHost = null;            try            {                getPersonDetailServiceHost = new ServiceHost(typeof(GetPersonDetailService));                getPersonDetailServiceHost.Open();                Console.WriteLine("GetPersonDetailService Started!");                Console.ReadKey();            }            catch(Exception ex)            {                Console.WriteLine(ex.StackTrace);            }            finally            {                getPersonDetailServiceHost.Close();            }        }    }}

(3)Client端代码

调用方法GetPersonDetail

using System;using System.ServiceModel;using Jackson0714.WcfServices.Service.Interface;namespace Jackson0714.WcfServices.Client{    class Program    {        static void Main(string[] args)        {            using (ChannelFactory<IGetPersonDetailService> channelFactory = new ChannelFactory<IGetPersonDetailService>("GetPersonDetailService"))            {                IGetPersonDetailService proxy = channelFactory.CreateChannel();                Console.WriteLine("Person Decription:{0}", proxy.GetPersonDetail("123").Description);            }            Console.Read();        }    }}

(4)接口

GetPersonDetail
using Jackson0714.WcfServices.Common;using System.ServiceModel;namespace Jackson0714.WcfServices.Service.Interface{    [ServiceContract(Name = "GetPersonDetailService", Namespace = "http://www.Jackson0714.com/")]    public interface IGetPersonDetailService    {        [OperationContract]        Person GetPersonDetail(string name);    }}

(5)实现接口方法

GetPersonDetail
using Jackson0714.WcfServices.Common;using Jackson0714.WcfServices.Service.Interface;namespace Jackson0714.WcfServices.Service{    public class GetPersonDetailService : IGetPersonDetailService    {        public Person GetPersonDetail(string name)        {            Person person = DataAccess.MockQueryPersonDetail(name);            return person;        }    }}

(6)Mock数据库访问层

MockQueryPersonDetail

模拟Person类的Description的数据量大小为100000字节

using Jackson0714.WcfServices.Common;using System.Text;namespace Jackson0714.WcfServices.Service{    class DataAccess    {        public static Person MockQueryPersonDetail(string name)        {             Person person = new Person();            person.Name = "Jackson0714";            string testString = "0123456789";            StringBuilder builder = new StringBuilder();            for(long i = 0;i<10000;i++)            {                builder.Append(testString);            }            person.Description = builder.ToString();            return person;        }    }}

(6)Person类

Person
namespace Jackson0714.WcfServices.Common{    public class Person    {        private string name;        public string Name        {            get            {                return this.name;            }            set            {                name = value;            }        }        private string description;        public string Description        {            get            {                return this.description;            }            set            {                description = value;            }        }    }}

 

1.2 分析结果

通过WireShare抓包,可以得到整个会话的总大小为25451 bytes (因为抓包时,有些数据丢失,所以数据包的大小小于远小于100000字节)

技术分享

经过压缩后,会话的总大小1071 bytes,远小于未压缩的数据量。

技术分享

1.3 打印窗口

 技术分享

2.使用JSON格式的数据进行传输

Server端首先将数据序列化为Json格式的数据,String类型,Client端接收到Json格式的数据后,反序列化为Json格式的数据。

需要引入Newtonsoft.Json.dll

下载地址:http://www.newtonsoft.com/json

2.1 Code的实现:

(1)定义接口

GetPersonDetailWithJson
using Jackson0714.WcfServices.Common;using System.ServiceModel;namespace Jackson0714.WcfServices.Service.Interface{    [ServiceContract(Name = "GetPersonDetailService", Namespace = "http://www.Jackson0714.com/")]    public interface IGetPersonDetailService    {        [OperationContract]        string GetPersonDetailWithJson(string name);    }}

(2)实现接口

GetPersonDetailWithJson

使用JsonConvert.SerializeObject(person)将person序列化为Json格式的数据。

public string GetPersonDetailWithJson(string name){     Person person = DataAccess.MockQueryPersonDetail(name);     return JsonConvert.SerializeObject(person);}

(3)客户端调用GetPersonDetailWithJson

使用JsonConvert.DeserializeObject<Person>(proxy.GetPersonDetailWithJson("123"))方法反序列化Json格式的数据,将Json格式的数据转换为Person对象。

using (ChannelFactory<IGetPersonDetailService> channelFactory = new ChannelFactory<IGetPersonDetailService>("GetPersonDetailService")){      IGetPersonDetailService proxy = channelFactory.CreateChannel();      Person person = JsonConvert.DeserializeObject<Person>(proxy.GetPersonDetailWithJson("123"));      Console.WriteLine("GetPersonDetailWithJson->Person Decription:{0}", person.Description); }

2.2 分析结果

由下面的图可以看出整个会话的数据传输大小为42878 bytes,减少了50%的数据。

这里有个问题,为什么Json格式的数据比原WCF基于XML传输的数据小???

原因是WCF的传输的数据是将对象序列化为xml格式,需要用很多标签来记录各个字段的内容。而用JSON格式的数据,已经将对象转化为键值对形式的数据,不包含标签,所以数据量减少了很多。

技术分享

2.3 打印窗口

技术分享

 

3.通过Json+压缩的方式传输

3.1 Code的实现

(1) 定义WCF压缩方式

<binaryMessageEncoding compressionFormat="GZip">

(2) 将对象序列化为Json格式的数据

JsonConvert.SerializeObject(person);

(3) 将Json格式的数据反序列化为对象

Person person = JsonConvert.DeserializeObject<Person>(proxy.GetPersonDetailWithJson("123"));

3.2 分析结果

从下图可以看出经过Json格式化然后压缩的数据为1004 bytes,未用Json格式化的数据为1071 bytes,减少了67个bytes。

 技术分享

 

4.通过压缩或Json格式化需要注意什么?

(1) 压缩或Json格式化需要消耗一定的资源,如果CPU和内存不足时,慎用压缩或Json格式化。

(2) 压缩或Json格式化需要消耗一定的时间,如果数据量很大,那么压缩或Json格式化的时间也很大,对于需要快速响应的系统,慎用压缩或Json格式化。

WCF传输1-你是否使用过压缩或Json序列化?