在Wcf中應用ProtoBuf替代默認的序列化器

  Google的ProtoBuf序列化器性能的牛逼已經有目共睹了,能夠把它應用到Socket通信,隊列,Wcf中,身爲dotnet程序員一邊期待着不久後Grpc對dotnet core的支持更期待着Wcf有一天能在Linux平臺上閃瞎全部人。如今簡單表述下Wcf中應用ProtoBuf替代默認的序列化器。git

準備:

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

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

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

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

 [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的引用並配置客戶端的調用信息:spa

  <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

  簡單測試一下:3d

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)

相關文章
相關標籤/搜索