为什么WCF在DataContract丢失时不会引发错误?
我遇到的问题是我是WCF的新手,只是在安装一些WCF net.tcp
客户端 - 服务器通信的过程中。为什么WCF在DataContract丢失时不会引发错误?
连接工作正常,但是当呼叫通过服务器时,传递的参数对象将所有字段设置为0
或null
。这是特别引人入胜的,因为我通过的类型
甚至不能构建为使所有字段为零
! (编辑:实际上,那会是真实的,如果该类型一直是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文章相矛盾。(除非 “不支持” 的意思是: “我们会默默地传递垃圾不告诉你”)
- VS 2010/.NET 4.0的WCF客户端和服务
- MyClassType + MYSTRUCT被"WCF will serialize Plain Old Class Objects correctly as long as you are on .Net 3.5 SP1 or later."
如果你的类有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这样做。
实际上最适合我的是如果WCF在遇到不定义数据合同的矿井类型时立即出错。你知道这是否有一个政策? – 2014-11-08 18:24:57
不是我所知道的。如果您不希望WCF将类作为数据合同对待,则不要在服务合同或错误合同中引用它。这只是编码纪律问题。只使用被设计为数据契约并被标记的类,那么您将获得可预测的行为并且没有令人讨厌的惊喜。 – 2014-11-08 18:39:37
你有一些不正确的假设。
您的第一个假设是WCF应该将所有对象视为可序列化的。这是一个错误的假设,因为对象通常具有运行时成员或计算成员,甚至是不可序列化的成员(比如Bitmaps,因为它们包含在不同计算机上毫无意义的显示硬件特定设备上下文)。
DataContracts是显式的(有一些例外),您必须定义您想要序列化的成员。如果您不包括成员,则不会生成错误,因为这是一种有效的情况,并且发生的次数比您想象的要多得多。
你的第二个假设是WCF使用构造函数来重建你的对象。它没有。它创建低级别的对象,否则它将无法序列化具有私有属性或字段的对象,并且您将被迫公开对象,或者创建不需要的构造函数来序列化它们。
你的第三个假设是WCF可以知道你打算在没有告诉它时做特定的事情。 WCF并不神奇,它无法读懂头脑。它只能在所知道的参数内工作。如果你不告诉它你想转移某些东西,它不会这样做(再次,通过约定定义某些例外)。
实际上,我只假设如果WCF不知道如何序列化某些东西,它至少在运行时会告诉我。为什么要悄悄地将垃圾转移到宝贵的地方,特别是在“数据合同明确”的情况下。什么是WCF知道的传输类型的用例既没有标记为Serializable也没有标记为DataContract? – 2014-11-09 09:45:25
如果您不添加DataContract,则序列化器假定您不想序列化该类,并且与数据库相同 – 2014-11-08 10:58:53
@pramod - dunno * it *假设的内容。 *我会*假设如果它不能/处理一个类型,它会引发一个错误,而不是悄悄地发送垃圾。 – 2014-11-08 13:48:14