1.当遇到需要传输大量数据时,怎么样传输数据?
2.压缩数据有哪几种常见的方式?
问题1解答:通过压缩来传输数据
问题2解答:
(1)WCF自带的压缩方式
(2)自定义WCF binding进行压缩
(3)将对象序列化为JSON格式
今天来探讨一下WCF自带的压缩方式Gzip和Json序列化
我的其他WCF文章:
先上图:
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格式化。