2011-08-19 108 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