我遇到的问题是我是WCF的新手,并且只是在绑定一些WCF net.tcp
客户端 - 服务器通信的过程中。
连接正常,但是当调用进入服务器时,传递的参数对象将所有字段都设置为0
或null
。这尤其令人着迷,因为传递 的类型I甚至无法构造为使所有字段为零 ! (编辑:实际上,如果该类型是class
,那么将为真,但它是一个结构,并且C#always has a parameterless constructor中设置了struct
所有字段都为零。问题的其余部分如所述。)
经过调查,似乎我必须为服务上的自定义参数指定DataContract
。我很好,我会添加它,它有望工作,我已经将DataContract添加到MyStruct
(仅),它现在可以工作,但我失败了得到原因:
为什么?为什么WCF在不告诉我的情况下转移垃圾?这是一个特征还是一个错误的?
如果重要,请参考以下类型草图:
....
[OperationContract]
void Append(List<MyClassType> lines);
....
// Note: No DataContract here whatsoever
public class MyClassType
{
private List<MyStruct> _values = new List<MyStruct>();
public IList<MyStruct> Values
{
get { return _values; }
}
....
// Note: No DataContract here whatsoever
public struct MyStruct
{
readonly int m_tag;
readonly float m_data;
public MyStruct(float data)
{
m_tag = 1; // m_tag is *never* 0
m_data = data;
....
在服务器端,我收到一个MyClassType
列表,其中Values
列表设置为正确的MyStruct
个实例数,但所有MyStruct
个对象都为零& #39; d out,尽管经常甚至无法构造m_tag
设置为零的对象!
深入挖掘(更新):到目前为止,答案一直很有帮助,但未能解决我的具体示例的为什么,也未能解决它没有&# 39; t似乎转移MyStruct
太有意义了 - 它甚至没有无参数构造函数!具体来说,我找到Types Supported by the Data Contract Serializer,其中指出:
DataContractSerializer ...支持许多其他类型,可以想到 有一个隐含的数据合同。以下是完整列表 可以序列化的类型:
MyStruct
(下面)显然不有一个无参数构造函数,但仍然会被转移并重建&#34;使用零字节。 这似乎与MSDN文章相矛盾。(除非&#34;不支持&#34;表示:&#34;我们将在不告诉您的情况下默默转移垃圾。&#34;)< / p>
答案 0 :(得分:4)
如果您的类没有WCF识别的序列化属性,那么WCF会将该类视为DataContract
,其所有公共字段和属性都为DataMember
。在3.5版中添加了此行为,并且由于您使用的是4.0版,因此您将看到该行为。创建类的版本并不重要,它是控制行为的WCF主机。
您看到m_tag = 0
因为DataContractSerializer
没有调用任何类构造函数。它使用GetUninitializedObject构造一个空白对象,然后从反序列化的数据流中设置所有字段值。如果邮件中的m_tag
元素包含0
,则该字段将以该值结束。如果消息中缺少m_tag
元素,它也将为零,因为默认情况下WCF数据协定成员是可选的。
避免此类问题的最佳方法是将所有数据合同视为哑数据传输对象,完全没有行为。任何字段验证都应该在服务操作中完成(无论如何这都是很好的安全措施)。但是,如果确实想要将此验证结果加入数据合同类,那么您可以使用OnDeserializingAttribute进行此操作。
答案 1 :(得分:3)
您有许多不正确的假设。
您的第一个假设是WCF应将所有对象视为可序列化。这是一个错误的假设,因为通常对象具有运行时成员或计算成员,甚至是不可序列化的成员(例如,位图,因为它们包含在不同计算机上无意义的显示硬件特定设备上下文)。
DataContracts是显式的(有一些例外),您必须定义要序列化的成员。如果您不包含成员,则不会产生错误,因为这是一种有效的情况,并且发生的次数比您想象的要多得多。
您的第二个假设是WCF使用构造函数来重建对象。它没有。它创建一个低级别的对象,否则它将无法序列化具有私有属性或字段的对象,并且您将被迫公开对象,或者创建您不需要的构造函数来序列化它们。 / p>
你的第三个假设是WCF可以知道你打算在没有告知的情况下做某些事情。 WCF并不神奇,它无法读懂思想。它只能在它所知道的参数范围内工作。如果你不告诉它你想转移什么东西,它就不会这样做(再次,通过惯例定义的某些例外)。