ProtoBuff.NET WCF - Неправильная ошибка проводного типа на клиенте
Мы используем ProtoBuff.NET с нашим сервисом WCF. ProtoBehavour был применен к интерфейсу, ProtoContract был применен к классу, а ProtoMember был применен к свойствам.
На стороне клиента мы добавили поведение protobuff в app.config, как показано ниже, однако, когда клиент запрашивает объект через службу WCF, мы получаем неверную ошибку типа проводника.
Удаление поведения ProtoBuff в службе приводит к нормальной работе службы.
Кто-нибудь может пролить свет на происходящее или направить нас в правильном направлении.
Мы используем связывание NET TCP.
Конфигурация клиента
<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>
Пример класса
<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
Выдержки конфигурации сервера
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)
2 ответа
Что касается комментария Марка, в котором он заявил, что существуют способы заставить protobuf-net работать вместе с командой SvcUtil или "Add Service Reference" VS, я нашел этот пост, где он говорит:
Re Order =..., стоило бы проверить содержимое; если они приходят с разными числами, есть способы исправить это с помощью частичного класса - безобразный хак, но в IIRC есть ProtoPartialMember (или аналогичный), который можно применить к классу, но который говорит об отдельном члене (свойстве / поле).
Тогда есть этот пост, где он говорит:
Есть 2 варианта исправить это; Первое (и самое простое) - использовать способность WCF делиться сборкой контракта между клиентом и сервером. Если вы сможете поделиться слоем DTO, все будет просто.
Во-вторых, добавить дополнительные маркеры на клиенте, чтобы дать ему подсказку. Вы можете сделать это через частичный класс, например, в отдельном кодовом файле (не редактируйте сгенерированный файл):
namespace YourNamespace {
[ProtoContract(DataMemberOffset = 1)] /* shift all DataMember orders */
public partial class tbEmployee {}
}
более явная альтернатива:
namespace YourNamespace {
[ProtoPartialMember(1, "EmployeeID")]
[ProtoPartialMember(2, "EmployeeName")]
public partial class tbEmployee {}
}
Если вы не разделяете сборки контракта на обслуживание, как предложено в ответе Марка, вам нужен способ заставить WCF использовать сериализатор ProtoBuf вместо сериализатора WCF по умолчанию в вашем клиентском коде. Проблема заключается в том, что маркировки атрибута ProtoBuf в контракте на обслуживание не будут присутствовать в документе WSDL, который обычно используется для генерации прокси-сервера службы в коде клиента.