views:

540

answers:

2

Hi,

I have a strange problem that's happening with my WCF REST service. For an operation where it accepts data, let's say it accepts the Foo class:

[WebInvoke(Method = "PUT", UriTemplate = "users/{username}")]
[OperationContract]
public void UpdateLoginUser(string username, LoginUser userUpdated) {
[...]
}

Now my LoginUser class inherits from my NormalUser class:

<DataContract()> _
Public MustInherit Class NormalUser
[...]
End Class

Public Class LoginUser
 Inherits NormalUser
[...]
End Class

When I PUT to my service, triggering UpdateLoginUser, everything works OK. However, if I apply DataContract to my NormalUser class:

<DataContract()> _
Public Class LoginUser
 Inherits NormalUser
[...]
End Class

... suddenly, the LoginUser class's constructor doesn't fire during deserialization! I have business login rules in there I need to run. So, why is it that when I apply the DataContract attribute to my inherited class, its constructor stops getting fired? How can I get around this? If I want to change namespace or name, I do need to apply the DataContract attribute.

+2  A: 

The DataContract (de)serializer does indeed NOT call the constructor.

That sounds odd and crazy - but that's the way it works, and there is no way to change this.

Because of this, the DataContract serializer also does NOT require a parameter-less constructor (like XmlSerializer or others).

Marc

marc_s
So why is it that if I don't specify DataContract, yet my class INHERITS from a class that does, the class that INHERITS *does* have its constructor called? :-) Isn't this totally inconsistent and wacky?
Jez
That's just the way WCF works. The DataContractSerializer will ONLY come into play for classes that have the [DataContract] attribute explicitly on them - it's **NOT** inherited from parent class to child class. That's just the way WCF was designed.
marc_s
+3  A: 

DataContractSerializer does not call the contract's constructor. If you want a method to run upon deserialization decorate it with the OnDeserializing attrbute:

When applied to a method, specifies that the method is called during deserialization of an object.

Your other option is to use XmlSerializer with WCF:

WCF also supports the XmlSerializer class. The XmlSerializer class is not unique to WCF. It is the same serialization engine that ASP.NET Web services use. The XmlSerializer class supports a much narrower set of types than the DataContractSerializer class, but allows much more control over the resulting XML and supports much more of the XML Schema definition language (XSD) standard. It also does not require any declarative attributes on the serializable types. For more information, see the XML Serialization topic in the .NET Framework documentation. The XmlSerializer class does not support data contract types.

Andrew Hare
This is a major PITA, because although I can apply OnDeserializing attribute to my constructor methods, what do I do about default values? (eh. Private xyz As String = "abc") - that initialization counts as part of the constructor, right, and it won't get done??
Jez
or use a method with the `[OnDeserialized]` attribute for a method that gets called AFTER the whole thing has been deserialized
marc_s
@jez9999: Do the member initialization inside the method as well. @marc_s: Right on - nice catch.
Andrew Hare