Protobuf-net WCF 响应为空
我有一个 WCF 合同,概述了一个测试方法,该方法仅使用 protobuf-net 在 WCF 中返回类的实例。我可以在测试应用程序中序列化和反序列化,但是当我通过 WCF 发出请求时,类实例的响应存在,但其所有属性均为 null。
以下是相关的配置文件和类定义:
[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 源代码,反序列化方法运行,它只是创建一个 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));
}
}
}
I have a WCF Contract outlining a test method that just returns an instance of a class across WCF using protobuf-net. I can serialize and deserialize in a test application but when I make the request via WCF the response the class instance exists, but all its properties are null.
Here are the relevant config files and class definitions:
[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>
I can debug the service and see the request come across. The TestClass object is created and returned. I stepped through protobuf-net source code and the deserialize method runs and it just creates a blank instance of TestClass and iterates through the data that is returned but never sets any of the properties.
Oh, I used Mex to generate a proxy.
EDIT
Here is the MEX generated class for 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));
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正确的;墨西哥/一代未包含这些数字,但您可以添加它们。在单独的代码文件(同一命名空间)中,添加
有时 WCF 有帮助,有时却很痛苦(请注意,如果两端都有共享的 DTO 程序集,则工作起来很容易)。
有时,WCF 会在每个 DataMember 上给出向右的数字,但相差 1 - 如果发生这种情况,您可以使用一个调整来告诉 protobuf 使用带有偏移量的这些数字。
Right; Mex/generation hasn't included the numbers, but you can add them. In a separate code file (same namespace), add
Sometimes WCF helps, sometimes it is a pain (note it works easy if you have a shared DTO assembly at both ends).
Sometimes WCF gives the right-ish numbers on each DataMember, but off-by-1 - if that happens there's a tweak you can use to just tell protobuf to use those numbers with an offset.
我认为您在这里遇到了著名的互操作性问题。请看我对这篇文章的回答:
在客户端这边,WCF操作合约的返回值为空!有解决方案吗?
您需要识别客户端代码期望的 Soap 消息以及正确的代码,以便与服务返回的 Soap 消息同步。
在此示例中,您可以通过以下方式确定客户端期望响应消息的格式:
I think you're hitting famous interoperability issue here. Please see my answer to this post:
At client side, return value of WCF Operation Contract is null ! Any solution?
You'd need to identify the Soap message expected by Client code and correct code to be in synch with Soap message being returned by service.
In this example, you can identify How Client expects response message to be formatted by following,