在Wcf中應用ProtoBuf替代預設的序列化器

来源:http://www.cnblogs.com/ylsforever/archive/2016/09/13/5865816.html
-Advertisement-
Play Games

Google的ProtoBuf序列化器性能的牛逼已經有目共睹了,可以把它應用到Socket通訊,隊列,Wcf中,身為dotnet程式員一邊期待著不久後Grpc對dotnet core的支持更期待著Wcf有一天能在Linux平臺上閃瞎所有人。現在簡單表述下Wcf中應用ProtoBuf替代預設的序列化器 ...


  Google的ProtoBuf序列化器性能的牛逼已經有目共睹了,可以把它應用到Socket通訊,隊列,Wcf中,身為dotnet程式員一邊期待著不久後Grpc對dotnet core的支持更期待著Wcf有一天能在Linux平臺上閃瞎所有人。現在簡單表述下Wcf中應用ProtoBuf替代預設的序列化器。

準備:

  首先,新建一套Wcf的解決方案,包含服務,宿主外加兩個客戶端用來測試調用:

  Wcf_ProtoBufSample.ClientViaMetaData會通過添加服務引用的方式調用服務,Wcf_ProtoBufSample.ClientViaReference則直接通過對Wcf_ProtoBufSample.Service添加引用來調動服務。

  分別為每個項目對protobuf-net添加引用: install-package protobuf-net -Version 2.0.0.668(此處現在比較糾結,protobuf-net的最新版本是2.1.0.0,但現在移除了ProtoBuf.ServiceModel,目測是為了相容dotnet core,估計以後還會再回來的。)

  接下來在Wcf_ProtoBufSample.Service中簡單定義個服務:

 [ServiceContract, ProtoContract]
    public interface IGreeterService
    {
        [OperationContract]
        Reply Get(Request request);
    }
    public class GreeterService : IGreeterService
    {
        public Reply Get(Request request)
        {
            Reply reply = new Reply() { GreetInfo = "你好!" + request.Name + ",恭喜你" + request.Age + "歲了!" };
            return reply;
        }
    }
    [DataContract]
    [ProtoContract]
    public class Request
    {
        [DataMember(Order = 0)]
        [ProtoMember(1)]
        public string Name { set; get; }
        [DataMember(Order = 1)]
        [ProtoMember(2)]
        public int Age { set; get; }
    }
    [DataContract]
    [ProtoContract]
    public class Reply
    {
        [DataMember(Order = 0)]
        [ProtoMember(1)]
        public string GreetInfo { set; get; }
    }
View Code

  代碼中對DataMember添加了Order的特性,方便過會用。

配置宿主

  在宿主中進行配置:

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="GreeterServiceBehavior" name="Wcf_ProtoBufSample.Service.GreeterService">
        <endpoint
          address="net.tcp://127.0.0.1:6978/GreeterService"
          binding="netTcpBinding"
          behaviorConfiguration="protoEndpointBehavior"
          bindingConfiguration="DefaultTcpBinding"
          contract="Wcf_ProtoBufSample.Service.IGreeterService">
        </endpoint>
        <endpoint
          address="net.tcp://127.0.0.1:6976/mex"
          binding="mexTcpBinding"
          contract="IMetadataExchange">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="GreeterServiceBehavior">
          <serviceMetadata/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="protoEndpointBehavior">
          <protobuf/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/>
      </behaviorExtensions>
    </extensions>
    <bindings>
      <netTcpBinding>
        <binding name="DefaultTcpBinding"
            closeTimeout="00:00:30"
            openTimeout="00:00:30"
            receiveTimeout="00:05:00"
            sendTimeout="00:50:00"
            transactionFlow="true"
            transferMode="Buffered"
            listenBacklog="100"
            maxBufferPoolSize="524288"
            maxBufferSize="6553600"
            maxConnections="100"
            maxReceivedMessageSize="6553600"  >
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
View Code

共用元數據的方式調用

  然後在Wcf_ProtoBufSample.ClientViaReference項目中添加對Wcf_ProtoBufSample.Service的引用並配置客戶端的調用信息:

  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="DefaultTcpBinding"
            closeTimeout="00:00:30"
            openTimeout="00:00:30"
            receiveTimeout="00:05:00"
            sendTimeout="00:50:00"
            transactionFlow="true"
            transferMode="Buffered"
            listenBacklog="100"
            maxBufferPoolSize="524288"
            maxBufferSize="6553600"
            maxConnections="100"
            maxReceivedMessageSize="6553600"  >
        </binding>
      </netTcpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="protoEndpointBehavior">
          <protobuf/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/>
      </behaviorExtensions>
    </extensions>
    <client>
      <endpoint address="net.tcp://127.0.0.1:6978/GreeterService" 
          binding="netTcpBinding"
          bindingConfiguration="DefaultTcpBinding" 
          contract="Wcf_ProtoBufSample.Service.IGreeterService"
          behaviorConfiguration="protoEndpointBehavior"
          name="GreeterService">
      </endpoint>
    </client>
  </system.serviceModel>
View Code

  簡單測試一下:

ChannelFactory<IGreeterService> factory = new ChannelFactory<IGreeterService>("GreeterService");
            IGreeterService client = factory.CreateChannel();
            var res = client.Get(new Request() {Name = "liam",Age = 18});
            Console.WriteLine(res.GreetInfo);
            Console.ReadKey();
View Code

通過添加服務引用或者WcfUtil

   添加服務引用才是我們的最愛,簡單快捷,易於維護:

在Wcf_ProtoBufSample.ClientViaMetaData中右鍵添加服務引用,這裡我公開的地址是:net.tcp://127.0.0.1:6976/mex,

  拿過來直接用肯定是不行的,畢竟我們已經修改了預設的序列化器,所以在配置中添加對ProtoBuf的配置信息,所以還是需要在配置中引用ProtoBuf的配置的:

 <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IGreeterService" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://127.0.0.1:6978/GreeterService" 
              behaviorConfiguration="protoEndpointBehavior"
              binding="netTcpBinding"
              bindingConfiguration="NetTcpBinding_IGreeterService" 
              contract="ServiceReference.IGreeterService"
              name="NetTcpBinding_IGreeterService">
                <identity>
                    <userPrincipalName value="DESKTOP-078UA43\admin" />
                </identity>
            </endpoint>
        </client>
        <behaviors>
      <serviceBehaviors>
        <behavior name="GreeterServiceBehavior">
          <serviceMetadata/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="protoEndpointBehavior">
          <protobuf/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/>
      </behaviorExtensions>
    </extensions>
    </system.serviceModel>
View Code

  簡單調用一下進行測試:

GreeterServiceClient client=new GreeterServiceClient("NetTcpBinding_IGreeterService");
            var res = client.Get(new Request() { Name = "liam", Age = 18 });
            Console.WriteLine(res.GreetInfo);
View Code

  運行後發現報錯了!

  細緻一些就不難發現,儘管我們的代理類生成的很簡單快捷,但公開元數據的描述不會包含ProtoBuf特性的描述,所以此時我們定義的 [DataMember(Order = 0)]的Order屬性此時就要發光發熱了!接下來要修改的就是生成的代理類,添加ProtoBuf的序列號特性,在類上標註ProtoContract特性在屬性上標註ProtoMember的特性,而且可以看著Order的順序就行標註:

ProtoBuf的序列化是有順序的,所以為了保證與服務端一致,此處需要謹慎(此處需要註意,更新服務引用小心自己定義的屬性被覆蓋)

簡單測試:

Over!

(備註:貌似這麼做比較複雜,畢竟開源的項目還是挺多的:https://github.com/maingi4/ProtoBuf.Services)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 看的代碼越多,寫的代碼越多,就越是享受這些字元,終於漸漸懂得了那種傳聞中的成就感,特別是自己從看不懂然後一步一步學,一個代碼一個代碼地敲,最後哪怕只是完成了一個小功能,也都是特別自豪的!這種自豪不用告訴別人,自己心裡就是特別滿足! 代碼最美的地方就在於所有的不可能都是有可能的...... 顯示的功能 ...
  • String和string的區別 從位置講: 1.String是.NET Framework裡面的String,小寫的string是C#語言中的string 2.如果把using System;刪掉,沒有大寫的String了,System是.NET Framework類庫中的一個函數名. 從性質講: ...
  • 後臺代碼: ...
  • Web.config配置: 在<system.web>節下: 登錄代碼: /// <summary> /// 登錄 /// </summary> public static bool Login(string userName, string userPwd) { MySqlHelper dbHel ...
  • 一、環境及工具 1、伺服器 VirtualBox5.1.4 安裝 Ubuntu Server 16.04 amd64 MySql Ver 14.14 Distrib 5.6.21 Jexus 5.8.1 nginx 1.10.0 dotnet core 1.0.0-preview2-003121 s ...
  • 隨著大規模的項目越來越多,許多項目都引入了依賴註入框架,其中最流行的有Castle Windsor, Autofac和Unity Container。 微軟在最新版的Asp.Net Core中自帶了依賴註入的功能,有興趣可以 "查看這裡" 。 關於什麼是依賴註入容器網上已經有很多的文章介紹,這裡我將 ...
  • 從微軟推出第一個版本的.NET Framework的時候,就在“System.Diagnostics”命名空間中提供了Debug和Trace兩個類幫助我們完成針對調試和跟蹤信息的日誌記錄。在.NET Framework 2.0中,微軟引入了TraceSource並對跟蹤日誌系統進行了優化,優化後的跟... ...
  • 將特定用戶代理的別名添加到用戶代理別名的內部集合中。 來自 <https://msdn.microsoft.com/zh-cn/library/6379d90d(v=vs.110).aspx> 用戶代理別名的集合指示 ASP.NET 伺服器控制項應為其呈現內容的目標用戶代理。其信息可以在Page.Cl ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...