2012-03-28 2 views
0

Wir verwenden ProtoBuff.NET mit unserem WCF-Dienst. ProtoBehavour wurde auf die Schnittstelle angewendet, ProtoContract wurde auf die Klasse & angewendet. ProtoMember wurde auf die Eigenschaften angewendet.ProtoBuff.NET WCF - Falsche Drahtfehler auf Client

Auf der Client-Seite haben wir das Verhalten von protobuff zu der app.config wie unten hinzugefügt, aber wenn der Client ein Objekt über den WCF-Dienst anfordert, erhalten wir einen falschen Drahtartfehler.

Das Entfernen des ProtoBuff-Verhaltens für den Dienst führt dazu, dass der Dienst ordnungsgemäß funktioniert.

Kann jemand bitte etwas Licht auf das, was passiert, oder zeigen uns in die richtige Richtung.

Wir verwenden die NET-TCP-Bindung.

Client-Konfiguration

<behaviors> 
     <endpointBehaviors> 
      <behavior name="ProtoBufBehaviorConfig"> 
       <ProtoBufSerialization/> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    <extensions> 
     <behaviorExtensions> 
      <add name="ProtoBufSerialization" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.480, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/> 
     </behaviorExtensions> 
    </extensions> 

Beispiel Klasse

<DataContract()> <ProtoBuf.ProtoContract()> _ 
Public Class Product 
    Private _ID As String 
    <DataMember(Order:=1)> <ProtoBuf.ProtoMember(1)> _ 
    Public Property ID As String 
     Get 
      Return _ID 
     End Get 
     Set(value As String) 
      _ID = value 
     End Set 
    End Property 

    Private _Name As String 
    <DataMember(Order:=2)> <ProtoBuf.ProtoMember(2)> _ 
    Public Property Name As String 
     Get 
      Return _Name 
     End Get 
     Set(value As String) 
      _Name = value 
     End Set 
    End Property 

    Private _Supplier As Supplier 
    <DataMember(Order:=3)> <ProtoBuf.ProtoMember(3)> _ 
    Public Property Supplier As Supplier 
     Get 
      Return _Supplier 
     End Get 
     Set(value As Supplier) 
      _Supplier = value 
     End Set 
    End Property 

    Private _Income_Group As Primary_Income_Group 
    <DataMember(Order:=4)> <ProtoBuf.ProtoMember(4)> _ 
    Public Property Primary_Income_Group As Primary_Income_Group 
     Get 
      Return _Income_Group 
     End Get 
     Set(value As Primary_Income_Group) 
      _Income_Group = value 
     End Set 
    End Property 

    Private _Margin_Percentage As Decimal 
    <DataMember(Order:=5)> <ProtoBuf.ProtoMember(5)> _ 
    Public Property Margin_Percentage As Decimal 
     Get 
      Return _Margin_Percentage 
     End Get 
     Set(value As Decimal) 
      _Margin_Percentage = value 
     End Set 
    End Property 

    Private _Cost_Price_exGST As Decimal 
    <DataMember(Order:=6)> <ProtoBuf.ProtoMember(6)> _ 
    Public Property Cost_Price_exGST As Decimal 
     Get 
      Return _Cost_Price_exGST 
     End Get 
     Set(value As Decimal) 
      _Cost_Price_exGST = value 
     End Set 
    End Property 

    Private _Retail_Price_incGST As Decimal 
    <DataMember(Order:=7)> <ProtoBuf.ProtoMember(7)> _ 
    Public Property Retail_Price_incGST As Decimal 
     Get 
      Return _Retail_Price_incGST 
     End Get 
     Set(value As Decimal) 
      _Retail_Price_incGST = value 
     End Set 
    End Property 

    Private _Active As Boolean 
    <DataMember(Order:=8)> <ProtoBuf.ProtoMember(8)> _ 
    Public Property Active As Boolean 
     Get 
      Return _Active 
     End Get 
     Set(value As Boolean) 
      _Active = value 
     End Set 
    End Property 

    Private _Image As String 
    <DataMember(Order:=9)> <ProtoBuf.ProtoMember(9)> _ 
    Public Property Image As String 
     Get 
      Return _Image 
     End Get 
     Set(value As String) 
      _Image = value 
     End Set 
    End Property 

    Private _Secondary_Income_Group As Secondary_Income_Group 
    <DataMember(Order:=10)> <ProtoBuf.ProtoMember(10)> _ 
    Public Property Secondary_Income_Group As Secondary_Income_Group 
     Get 
      Return _Secondary_Income_Group 
     End Get 
     Set(value As Secondary_Income_Group) 
      _Secondary_Income_Group = value 
     End Set 
    End Property 
End Class 

Server Config Auszüge

Dim TCPBinding As NetTcpBinding = New NetTcpBinding With { _ 
       .PortSharingEnabled = True, _ 
       .ListenBacklog = 5000, _ 
       .ReaderQuotas = New System.Xml.XmlDictionaryReaderQuotas With {.MaxArrayLength = Integer.MaxValue, .MaxBytesPerRead = Integer.MaxValue, .MaxDepth = Integer.MaxValue, .MaxNameTableCharCount = Integer.MaxValue, .MaxStringContentLength = Integer.MaxValue}, _ 
       .MaxConnections = 10000, _ 
       .TransferMode = TransferMode.Buffered, _ 
       .MaxBufferSize = Integer.MaxValue, _ 
       .MaxReceivedMessageSize = Integer.MaxValue, _ 
       .ReliableSession = New System.ServiceModel.OptionalReliableSession With {.Enabled = False}, _ 
       .Security = New System.ServiceModel.NetTcpSecurity With { _ 
                 .Mode = SecurityMode.Transport, _ 
                 .Transport = New System.ServiceModel.TcpTransportSecurity With {.ProtectionLevel = Net.Security.ProtectionLevel.Sign, .ClientCredentialType = TcpClientCredentialType.Windows} _ 
                } _ 
      } 
..... 
Dim endpoint As ServiceEndpoint = ServiceHostObject.AddServiceEndpoint(Contract, TCPBinding, "") 
endpoint(New ProtoBuf.ServiceModel.ProtoEndpointBehavior) 
+0

Entschuldigung für die Verzögerung; Kannst du klarstellen: das andere Ende der Verbindung - benutzt es die gleichen Typen (Assembly-Sharing) oder verwendet es generierte Proxy-Typen (svcutil/etc)? Beides kann funktionieren - aber ich muss wissen, was ich richtig beantworten soll. –

Antwort

0

Wenn Sie die Servicevertragsassemblys nicht teilen, wie in answer von Marc vorgeschlagen, benötigen Sie eine Möglichkeit, damit WCF den ProtoBuf-Serializer anstelle des WCF-Standardserialisers in Ihrem Clientcode verwendet. Das Problem ist, dass die ProtoBuf-Attributmarkierungen im Servicevertrag nicht im WSDL-Dokument sind, das normalerweise zum Generieren des Dienstproxys im Clientcode verwendet wird.

+0

Danke - Was ist die empfohlene Praxis, um die Verwendung von protobuff.net zu ermöglichen, wenn Sie keine Assemblys teilen? – Luke

+0

Das automatische Generieren des Dienstproxys mit "Add Service Reference" oder mithilfe von SvcUtil führt bei der Verwendung von ProtoBuf wirklich nicht zu einer Verbesserung. Der Grund dafür ist, dass Sie den resultierenden Code mit dem Attribut "ProtoMember" genau so annotieren müssen, wie es im Servicevertrag der Fall ist. Wenn Sie das versauen oder den Proxy regenerieren, dann sind Sie zurück zu dem, was Sie jetzt sehen. Sie könnten den Servicevertragscode teilen, aber dann müssten Sie zwei Serviceverträge (Client & Service) erstellen und warten. Wenn Sie ProtoBuf verwenden, bleiben Sie beim Teilen der Servicevertrags-Assembly und sparen Sie sich etwas Arbeit. –

+0

@Sixto tatsächlich gibt es Möglichkeiten, das zu machen –

0

In Bezug auf Marc Kommentar, wo er feststellte, dass es Wege protobuf-net Arbeit zusammen mit SvcUtil oder „Dienstverweis hinzufügen“ VS-Befehl, fand ich this Post, wo er sagt, machen:

Re Order = ..., es lohnt sich, den Inhalt zu überprüfen; Wenn sie mit verschiedenen Zahlen kommen, gibt es Möglichkeiten, dies über eine partielle Klasse zu beheben - ein hässlicher Hack, aber IIRC gibt es ProtoPartialMember (oder ähnlich), die auf die Klasse angewendet werden kann, aber die über ein einzelnes Mitglied (Eigenschaft /Feld).

Dann gibt es this Post, wo er sagt:

Es gibt 2 Möglichkeiten für diese Festsetzung; Das erste (und einfachste) ist die Verwendung der WCF-Funktion zum Freigeben einer Vertragsassembly zwischen Client und Server. Wenn Sie die DTO-Ebene teilen können, wird das die Dinge einfach halten.

Die zweite besteht darin, dem Client zusätzliche Marker hinzuzufügen, um einen Hinweis darauf zu geben.Sie können über eine Teil-Klasse dies tun, zum Beispiel in einer separaten Code-Datei (keine Änderungen vornehmen, die generierte Datei):

namespace YourNamespace { 
    [ProtoContract(DataMemberOffset = 1)] /* shift all DataMember orders */ 
    public partial class tbEmployee {} 
} 

eine explizitere Alternative ist:

namespace YourNamespace { 
    [ProtoPartialMember(1, "EmployeeID")] 
    [ProtoPartialMember(2, "EmployeeName")] 
    public partial class tbEmployee {} 
}