The problem I have is that I'm new to WCF, and just in the process of rigging up some WCF net.tcp
client-server communication.
The connection worked fine, but when the call goes through to the server, the passed parameter object has all fields set to 0
or null
. This is especially fascinating as the type I'm passing cannot even be constructed to have all fields zero! (edit: actually, that would have been true if that type had been a class
, but it is a struct, and struct
in C# always has a parameterless constructor that sets all field to zero. The rest of the problem stands as described.)
After investigation, it seems that I must specify a DataContract
for my custom parameters on the service. I'm fine with that, I'll add it and it will hopefully work, I have added DataContract to MyStruct
(only) and it now works, but I fail to get why:
Why is that? Why is WCF transferring garbage without telling me? Is it a feature or a misfeature?
If it matters, here's a sketch of the types involved:
....
[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;
....
On the server side, I receive a list of MyClassType
with the Values
list set to the correct number of MyStruct
instances, but all the MyStruct
object are zero'd out, even though regularly it is not even possible to construct such an object with m_tag
set to zero!
Digging deeper (update): Answers so far have been helpful, but fail to address the why of my specific example, and also fail to address that it doesn't seem to make too much sense to transfer MyStruct
- it doesn't even have a parameterless constructor! Specifically, I found Types Supported by the Data Contract Serializer, which states:
The DataContractSerializer ... supports many other types, which can be thought of as having an implicit data contract. The following is a complete list of types that can be serialized:
MyStruct
(below) clearly does not have a parameterless constructor, and still it is transferred and "reconstructed" using zero bytes. This seems to contradict the MSDN article. (Unless "not supported" means: "We'll silently transfer garbage without telling you.")
If your class has no serialization attributes recognised by WCF, then WCF will treat the class as if it was a DataContract
with all public fields and properties as DataMember
s. This behaviour was added in version 3.5, and since you are on version 4.0, you will see that behaviour. The version that your class was created with is not important, it's the WCF host that controls the behaviour.
You see m_tag = 0
because the DataContractSerializer
does not call any of your class constructors. It constructs a blank object using GetUninitializedObject, then it sets all field values from the deserialised data stream. If the m_tag
element in the message contains 0
, then the field will end up with that value. It will also be zero if the m_tag
element is missing from the message, since WCF data contract members are optional by default.
The best way to avoid problems like this is to regard all your data contracts as dumb data transfer objects, with no behaviour at all. Any field validation should be done inside the service operation (which is good security practice anyway). However, if you really want to bake this validation into the data contract class, then you can do so with OnDeserializingAttribute.