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抓包,可以得知Response的數據大小為Content-Length: 100352 bytes。

經過壓縮后,Response的數據大小為Content-Length: 506 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 分析結果

通過WireShare抓包,可以得知Response的數據大小為Content-Length: 100263bytes。比未經過序列化的數據減少了89 bytes的數據。

這里有個問題,為什么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格式化。

 

5.參考資料

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

https://msdn.microsoft.com/en-us/library/ms751458(v=vs.110).aspx

 

 

我的其他WCF文章:

WCF安全1-開篇

WCF安全2-非對稱加密

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

WCF傳輸1-你是否使用過壓縮或Json序列化?

 

 

 


作  者: Jackson0714
出  處:http://www.cnblogs.com/jackson0714/
關於作者:專注於微軟平台的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM