为什么WCF在DataContract丢失时不会引发错误?

时间:2014-11-08 10:18:43

标签: c# .net wcf serialization datacontract

我遇到的问题是我是WCF的新手,并且只是在绑定一些WCF net.tcp客户端 - 服务器通信的过程中。

连接正常,但是当调用进入服务器时,传递的参数对象将所有字段都设置为0null。这尤其令人着迷,因为传递 的类型I甚至无法构造为使所有字段为零 ! (编辑:实际上,如果该类型是class,那么为真,但它是一个结构,并且C#always has a parameterless constructor中设置了struct所有字段都为零。问题的其余部分如所述。)

经过调查,似乎我必须为服务上的自定义参数指定DataContract。我很好,我会添加它,它有望工作,我已经将DataContract添加到MyStruct(仅),它现在可以工作,但我失败了得到原因:

  • 没有编译错误
  • 没有运行时错误(来自WCF - 我的代码触发无效字段的断言)
  • WCF显然正在转移一个类型并重建对象,甚至没有使用对象的c&#tor; tor。 (并将所有内容归零)

为什么?为什么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>


2 个答案:

答案 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并不神奇,它无法读懂思想。它只能在它所知道的参数范围内工作。如果你不告诉它你想转移什么东西,它就不会这样做(再次,通过惯例定义的某些例外)。