2011-08-19 111 views
3

我有一个带有HTTP绑定的WCF服务,它返回500k大小的数据集。 当使用WCF默认的日志,我可以看到的消息和数据被转移,每条消息NetTCP和二进制传输

<system.serviceModel> 
    <!-- add trace logging --> 
    <diagnostics wmiProviderEnabled="true"> 
     <messageLogging 
      logEntireMessage="true" 
      logMalformedMessages="true" 
      logMessagesAtServiceLevel="true" 
      logMessagesAtTransportLevel="true" 
      maxMessagesToLog="3000" 
     /> 
    </diagnostics> 

    .... 

    <system.diagnostics> 
    <sources> 
     <source name="System.ServiceModel.MessageLogging"> 
     <listeners> 
      <add type="System.Diagnostics.DefaultTraceListener" name="Default"> 
      <filter type="" /> 
      </add> 
      <add initializeData="c:\nettcpTestLOCALToTEST.xml" type="System.Diagnostics.XmlWriterTraceListener" 
      name="messages"> 
      <filter type="" /> 
      </add> 
     </listeners> 
     </source> 
    </sources> 
    </system.diagnostics> 

的一点是,我正在寻找一种方式,以减少服务器和客户端之间的流量,我已被告知,NetTCP正在传输数据二进制文件?那是对的吗?

我已经建立了一个NetTCPBinding的测试场景,当我在客户端读取WCF时,响应消息包含了XML格式的整个数据集模式和数据。它是否只是序列化,以便可以写入日志,或者是否将此消息转换为二进制文件?

NetTCP绑定的数据传输量是否小于HTTPBinding?它是文本还是二进制文件?

在此先感谢

回答

3

是信息将被转移二进制,但(我假设的DataContractSerializer)的串行器将序列化XML格式的数据:

使用的DataContractSerializer类序列化和反序列化的情况下,一个类型到XML流或文档

DataContractSerializer 从实况:

NetTcpBinding默认生成一个运行时通信堆栈,它使用传输安全性,TCP用于消息传递以及二进制消息编码。此绑定是通过Intranet进行通信的适当系统提供的选择。

NetTcpBinding MSDN

如果您选择实现ISerializable的,你可以使用WCF太多,但你必须实现一个DataContractResolver化解类型:如果客户“知道”的类型(例如,你把它们放在一个dll并将它们添加到客户端应用程序),您可以使用下面的示例代码(对不起,我只在F#中有这个,但应该会发现很容易翻译) 这应该会以更紧凑的形式产生序列化。



type internal SharedTypeResolver() = 
    inherit System.Runtime.Serialization.DataContractResolver() 

    let dict = new Xml.XmlDictionary() 

    override this.TryResolveType(t : Type, declaredT : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver, typeName : Xml.XmlDictionaryString byref, typeNamespace : Xml.XmlDictionaryString byref) = 
     typeNamespace = dict.Add(t.Assembly.FullName) 
     typeName = dict.Add(t.FullName) 
     true 

    override this.ResolveName(typeName : string, typeNamespace : string, declaredType : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver) = 
     let res = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) 
     if res = null then Type.GetType(typeName + ", " + typeNamespace) else res 

PS:发现了同样在C#:


    public class SharedTypeResolver : DataContractResolver 
    { 
     #region Overrides of DataContractResolver 

     /// 
     /// Override this method to map a data contract type to an xsi:type name and namespace during serialization. 
     /// 
     /// 
     /// true if mapping succeeded; otherwise, false. 
     /// 
     /// The type to map.The type declared in the data contract.The known type resolver.The xsi:type name.The xsi:type namespace. 
     public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) 
     { 
      if (!knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace)) 
      { 
       var dict = new XmlDictionary(); // nice trick to get the right type for typeName 
       if (type != null) 
       { 
        typeNamespace = dict.Add(type.Assembly.FullName); 
        typeName = dict.Add(type.FullName); 
       } 
       else 
       { 
        typeNamespace = dict.Add("noAss"); 
        typeName = dict.Add("noType"); 
       } 
      } 
      return true; 
     } 

     /// 
     /// Override this method to map the specified xsi:type name and namespace to a data contract type during deserialization. 
     /// 
     /// 
     /// The type the xsi:type name and namespace is mapped to. 
     /// 
     /// The xsi:type name to map.The xsi:type namespace to map.The type declared in the data contract.The known type resolver. 
     public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) 
     { 
      return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? 
        Type.GetType(typeName + ", " + typeNamespace); 
     } 

(请注意:计算器不喜欢assignmentoperator “< - ” 从F#,我不知道如何规避 - 因此,我用“=”) 噢 - 我想我不得不说如何将这些解析器添加到您的主机:


     private static void AddResolver(OperationDescription operationDescription) 
     { 
      if (operationDescription == null) 
       throw new ArgumentNullException(); 

      var serializationBehavior = operationDescription.Behaviors.Find(); 
      if (serializationBehavior == null) 
      { 
       serializationBehavior = new DataContractSerializerOperationBehavior(operationDescription); 
       operationDescription.Behaviors.Add(serializationBehavior); 
      } 
      serializationBehavior.DataContractResolver = new SharedTypeResolver(); 
     } 

使用这种搭配:



      var contrDescription = _host.Description.Endpoints[0].Contract; 
      var description= contrDescription.Operations.Find("MyServiceMethod"); 
      AddResolver(description); 


通过您的服务方法的名称取代“MyServiceMethod”(每方法调用或您遍历所有的)

+0

的感谢!但如果我没有实现解析器类,通过网络传输的数据是否仍然少于使用HttpBinding? – Martin

+0

如果没有解析器,你的客户端不会知道如何处理数据(但是尝试一下:自从我写这个以后 - 也许他们在你的程序集中寻找已知类型 - 但我怀疑它是因为在开始时你必须在你的合同定义中添加额外的“KnownTypes”) – Carsten

+0

这是一篇很好的文章:http://blogs.msdn.com/b/youssefm/archive/2009/06/05/introducing-a-new-datacontractserializer -feature-the-datacontractresolver.aspx(嗯,我想我只是可以链接这个...我的代码是直接从这篇文章;)) – Carsten