zoukankan      html  css  js  c++  java
  • 在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-078UA43admin" />
                    </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)

  • 相关阅读:
    解决:信息中插入avi格式的视频时,提示“unsupported video format”
    java字节数组和16进制之间的转换
    16进制转换字节数组工具类
    如何在ubuntu 12.04 中安装经典的 GNOME桌面
    Ubuntu安装软件提示”需要安装不能信任的软件包”解决办法
    Ubuntu系统下运行Eclipse出现找不到jre的问题的解决方法
    ubuntu添加共享出错
    从scrapy使用经历说开来
    有趣的问题--12 coins problem
    一个奇怪的MySQL错误返回
  • 原文地址:https://www.cnblogs.com/ylsforever/p/5865816.html
Copyright © 2011-2022 走看看