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

问题描述:

我遇到的问题是我是WCF的新手,只是在安装一些WCF net.tcp客户端 - 服务器通信的过程中。为什么WCF在DataContract丢失时不会引发错误?

连接工作正常,但是当呼叫通过服务器时,传递的参数对象将所有字段设置为0null。这是特别引人入胜的,因为我通过的类型 甚至不能构建为使所有字段为零 ! (编辑:实际上,那是真实的,如果该类型一直是class,但它是一个结构,而在C#always has a parameterless constructorstruct设置所有的字段设置成0描述问题的其他代表。)

经过调查后,我似乎必须为我的服务上的自定义参数指定DataContract。我很好的是, 我来补充它,它会希望工作, 我已经加入到DataContract MyStruct(只),它现在的作品,但我不明白为什么:

  • 没有编译错误
  • 没有运行时错误(来自WCF--我的代码触发了无效字段的断言)
  • WCF显然是在不使用对象的c'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实例,但是所有的对象都被清零了,尽管通常情况下甚至不可能将m_tag设置为0来构建这样的对象!


进一步挖掘(更新):到目前为止的答案是有帮助的,但未能解决我的具体例子的为什么,也未能解决,似乎它并没有做出太大感觉转移MyStruct - 它甚至没有无参数的构造函数!具体而言,我发现Types Supported by the Data Contract Serializer,其中指出:

DataContractSerializer的...支持许多其他类型的,它可以被认为是 为具有一个隐含的数据契约。以下是类型的完整列表 可序列化:

  • 那有没有参数的构造函数的所有公开可见的类型。
  • ...

MyStruct(下面)显然不有参数的构造函数,并且仍然将其转移和“重构”使用零个字节。 这似乎与MSDN文章相矛盾。(除非 “不支持” 的意思是: “我们会默默地传递垃圾不告诉你”)


+0

如果您不添加DataContract,则序列化器假定您不想序列化该类,并且与数据库相同 – 2014-11-08 10:58:53

+0

@pramod - dunno * it *假设的内容。 *我会*假设如果它不能/处理一个类型,它会引发一个错误,而不是悄悄地发送垃圾。 – 2014-11-08 13:48:14

如果你的类有WCF没有识别出系列化的属性,然后WCF将把类,仿佛它是一个DataContract一切:在设置为面向.NET 3.0想这可能是相关的组件定义公共领域和prope作为DataMember s。此行为已在版本3.5中添加,并且由于您使用的是4.0版本,因此您将看到该行为。您的类创建的版本并不重要,它是控制行为的WCF主机。

你会看到m_tag = 0,因为DataContractSerializer没有调用任何类的构造函数。它使用GetUninitializedObject构造一个空白对象,然后它设置来自反序列化数据流的所有字段值。如果消息中的m_tag元素包含0,则字段将以该值结束。如果消息中缺少m_tag元素,它也将为零,因为默认情况下WCF数据协定成员是可选的。

避免这种问题的最好方法是将所有数据合同视为哑数据传输对象,根本没有任何行为。任何字段验证都应该在服务操作中完成(无论如何,这是很好的安全实践)。但是,如果您真的要要将此验证纳入数据合同类,那么您可以使用OnDeserializingAttribute这样做。

+0

实际上最适合我的是如果WCF在遇到不定义数据合同的矿井类型时立即出错。你知道这是否有一个政策? – 2014-11-08 18:24:57

+0

不是我所知道的。如果您不希望WCF将类作为数据合同对待,则不要在服务合同或错误合同中引用它。这只是编码纪律问题。只使用被设计为数据契约并被标记的类,那么您将获得可预测的行为并且没有令人讨厌的惊喜。 – 2014-11-08 18:39:37

你有一些不正确的假设。

您的第一个假设是WCF应该将所有对象视为可序列化的。这是一个错误的假设,因为对象通常具有运行时成员或计算成员,甚至是不可序列化的成员(比如Bitmaps,因为它们包含在不同计算机上毫无意义的显示硬件特定设备上下文)。

DataContracts是显式的(有一些例外),您必须定义您想要序列化的成员。如果您不包括成员,则不会生成错误,因为这是一种有效的情况,并且发生的次数比您想象的要多得多。

你的第二个假设是WCF使用构造函数来重建你的对象。它没有。它创建低级别的对象,否则它将无法序列化具有私有属性或字段的对象,并且您将*公开对象,或者创建不需要的构造函数来序列化它们。

你的第三个假设是WCF可以知道你打算在没有告诉它时做特定的事情。 WCF并不神奇,它无法读懂头脑。它只能在所知道的参数内工作。如果你不告诉它你想转移某些东西,它不会这样做(再次,通过约定定义某些例外)。

+0

实际上,我只假设如果WCF不知道如何序列化某些东西,它至少在运行时会告诉我。为什么要悄悄地将垃圾转移到宝贵的地方,特别是在“数据合同明确”的情况下。什么是WCF知道的传输类型的用例既没有标记为Serializable也没有标记为DataContract? – 2014-11-09 09:45:25