Luke
Luke

Reputation: 1

ProtoBuff.NET WCF - Incorrect wire-type error on client

We are using ProtoBuff.NET with our WCF service. ProtoBehavour has been applied to the interface, ProtoContract has been applied to the class & ProtoMember has been applied to the properties.

On the client side we have added the protobuff behavior to the app.config as below however when the client requests a object via the WCF service we receive a incorrect wire type error.

Removing the ProtoBuff behavior on the service results in the service working fine.

Can anybody please shed some light on what is happening or point us in the right direction.

We are using the NET TCP binding.

Client Configuration

<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>

Example Class

<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 Excerpts

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)

Upvotes: 0

Views: 944

Answers (2)

Dejan Janjušević
Dejan Janjušević

Reputation: 3230

In regard to Marc's comment where he stated that there were ways to make protobuf-net work along with SvcUtil or "Add Service Reference" VS command, I found this post, where he says:

Re Order=..., it would be worth checking the contents; if they are coming up with different numbers, there are ways to fix this via a partial class - an ugly hack, but IIRC there is ProtoPartialMember (or similar) that can be applied to the class, but which talks about an individual member (property/field).

Then there is this post, where he says:

There are 2 options for fixing this; the first (and easiest) is to use WCF's ability to share a contract assembly between client and server. If you can share the DTO layer, that'll keep things simple.

The second is to add additional markers at the client to give it a clue. You can do this via a partial class, for example in a separate code file (don't edit the generated file):

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

a more explicit alternative is:

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

Upvotes: 0

Sixto Saez
Sixto Saez

Reputation: 12680

If you are not sharing the service contract assemblies as suggested in marc's answer then you need a way to make WCF use the ProtoBuf serializer instead of the WCF default serializer in your client code. The problem is the ProtoBuf attribute markings in the service contract will not be in the WSDL document that is normally used to generate the service proxy in the client code.

Upvotes: 0

Related Questions