Protobuf-net WCF-ответ пуст
У меня есть контракт WCF, описывающий метод тестирования, который просто возвращает экземпляр класса через WCF с использованием protobuf-net. Я могу сериализовать и десериализовать в тестовом приложении, но когда я делаю запрос через WCF, отклик экземпляра класса существует, но все его свойства равны нулю.
Вот соответствующие файлы конфигурации и определения классов:
[ProtoContract]
public class TestClass
{
[ProtoMember(1)]
public int TestInt { get; set; }
[ProtoMember(2)]
public string TestString { get; set; }
}
...
[ServiceContract]
public interface ITestService
{
[OperationContract]
[ProtoBehavior]
TestClass RunTest(int x);
}
...
<extensions>
<behaviorExtensions>
<add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=1.0.0.282, Culture=neutral, PublicKeyToken=257b51d87d2e4d67" />
</behaviorExtensions>
</extensions>
<endpointBehaviors>
<behavior name="Proto.Default.EndpointBehavior">
<protobuf />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Proto.Default.ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata />
<serviceAuthorization principalPermissionMode="None" />
<serviceThrottling maxConcurrentCalls="250"
maxConcurrentSessions="200"
maxConcurrentInstances="10" />
</behavior>
</serviceBehaviors>
...
<services>
<service name="WcfTestService" behaviorConfiguration="Proto.Default.ServiceBehavior">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ITestService" contract="ITestService" behaviorConfiguration="Proto.Default.EndpointBehavior" />
<endpoint address="mex" binding="customBinding" bindingConfiguration="myMexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:2517/TestService" />
</baseAddresses>
</host>
</service>
...
<client>
<endpoint address="net.tcp://localhost:2517/TestService"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ITestService"
contract="ITestService" name="TestService"
behaviorConfiguration="Proto.Default.EndpointBehavior">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
Я могу отладить сервис и посмотреть, как попал запрос. Объект TestClass создан и возвращен. Я прошел через исходный код protobuf-net, и метод deserialize запускается, и он просто создает пустой экземпляр TestClass и выполняет итерацию по возвращаемым данным, но никогда не устанавливает никаких свойств.
О, я использовал Mex для генерации прокси.
РЕДАКТИРОВАТЬ
Вот сгенерированный MEX класс для TestClass
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="TestClass", Namespace="http://schemas.datacontract.org/2004/07/TestProject")]
[System.SerializableAttribute()]
public partial class TestClass : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int TestIntField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string TestStringField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public int TestInt {
get {
return this.TestIntField;
}
set {
if ((this.TestIntField.Equals(value) != true)) {
this.TestIntField = value;
this.RaisePropertyChanged("TestInt");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string TestString {
get {
return this.TestStringField;
}
set {
if ((object.ReferenceEquals(this.TestStringField, value) != true)) {
this.TestStringField = value;
this.RaisePropertyChanged("TestString");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
2 ответа
Правильно; Мекс / поколение не включает числа, но вы можете добавить их. В отдельном файле кода (то же пространство имен) добавьте
[ProtoContract]
[ProtoPartialMember(1, "TestInt")]
[ProtoPartialMember(2, "TestString")]
partial class TestClass {}
Иногда помогает WCF, иногда это больно (обратите внимание, это работает легко, если у вас есть общая сборка DTO на обоих концах).
Иногда WCF дает правильные числа для каждого DataMember, но не на 1 - если это происходит, вы можете использовать твик, чтобы просто сказать protobuf использовать эти числа со смещением.
Я думаю, что вы столкнулись с известной проблемой совместимости здесь. Пожалуйста, смотрите мой ответ на этот пост: на стороне клиента возвращаемое значение операционного контракта WCF равно нулю! Любое решение?
Вам нужно будет определить сообщение Soap, ожидаемое кодом клиента, и правильный код, который будет синхронизирован с сообщением Soap, возвращаемым службой.
В этом примере вы можете определить, как клиент ожидает, что ответное сообщение будет отформатировано, выполнив
a. creating Service stub from WSDL using WSDL /serverInterface
b. Create a class implimenting the Service stub
c. Host the WebService in IIS and browse the help page
d. Click on operation called from list.
e. Help page shows the expected request and response soap message