T
Techno_Dex
I'm stumbling through a few things with the DataContractSerializer and the
changes made as of 3.5 SP1 and hope someone can shed some light on and/or
confirm my thoughts as to what is occuring. I have a bunch of objects which
started out as simple POCO types and were decorated with the [Serializable]
attribute. Somewhere a long the lines one of our developers changes up one
of the base classes to also include the [DataContract] attributes (and
[DataMember] etc). The serializer code was changed over to use the
DataContractSerializer in conjunction with a MemoryStream and XmlTextWriter
to retrieve a string which could be passed to a third party. With the
DataContractSerializer changes made in SP1, the [DataContract] attribute is
no longer needed in order to serialize "simple" objects, so again one of our
developers decided to remove "most" of the [Serializable] attributes which
competely clobbered everything pending in the third party system. What
appears to have been happening is when the [DataContract] and [Serializable]
classes were serialized via the DataContractSerializer, the base class had
all public properties serialized (using the public property's names) and all
the individual objects (decorated with the [Serializable] attribute) within
a collection had their name serialized correctly but all of the other values
which were serializer were the private member variables behind the public
properties of the classed marked as [Serializable]. When I stripped off the
[DataContract] and [Serializable] attributes on everything and ran though
the same DataContractSerializer code, everything serialized as expected
using only the public properties (and the appropriate names). One major
problem I have with the DataContractSerializer is when you try to
deserialize from the first example using objects from the second example, no
Exceptions are thown at all. The objects are created as shells and only the
[DataMember] decorated values are populated which means the rest of the data
was dumped/lost in deserialization. Now most of the documentation out on
the web is from everyone using the original functionality (and most haven't
updated it with the new details) so it's a little confusing, but my
assumption is that which using mixed attributes on objects (i.e.
[DataContract] and [Serializable] that when the DataContractSerializer hits
the [Serializable] objects is grabs the private data instead of the public
data. This seams odd to me as I would expect it to serialize everything
both public and private if it was going to grab the private data, but this
is not the case. I have no idea why the items in the collection have their
names serialized correctly. My guess would be maybe its picking up the
BaseObj's [DataContract] attribute somehow. Can someone confirm any of this
or point me in the right direction to get the DataContractSerializer to
operate on the public properties instead of the private members when dealing
with a mixed [DataContract], [Serializable] bag of objects?
Objects
======================
[DataContract]
public class BaseObj
{
private bool _HasChanges;
private bool _IsNew;
[DataMember]
public bool HasChanges
{
get {return _HasChanges;}
set {_HasChanges = value;}
}
[DataMember]
public bool IsNew
{
get {return _IsNew;}
set {_IsNew = value;}
}
}
[Serializable]
public class RootObj : BaseObj
{
private int _key;
private string _name;
private ObservableCollection<Widget> _widgets;
public int Key
{
get {return _key;}
set {_key= value;}
}
public int Name
{
get {return _name;}
set {_name= value;}
}
public ObservableCollection<Widget> Widgets
{
get
{
if (_widgets == null}
_widgets = new ObservableCollection<Widget>();
return _widgets;
}
set {_widgets= value;}
}
}
[Serializable]
public class Widget: BaseObj
{
private int _key;
private DateTime _Date;
private ObservableCollection<Widget> _widgets;
public int Key
{
get {return _key;}
set {_key= value;}
}
public DateTime Date
{
get {return _Date;}
set {_Date= value;}
}
}
Serialized String Output
======================
<RootObj>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>12345</_key>
<_name>TestName</_name>
<_widgets>
<Widget>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>1</_key>
<_Date>2009-12-1 1:00:00</_Date>
<Widget>
<Widget>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>2</_key>
<_Date>2009-11-15 1:00:00</_Date>
<Widget>
</_widgets>
</RootObj>
changes made as of 3.5 SP1 and hope someone can shed some light on and/or
confirm my thoughts as to what is occuring. I have a bunch of objects which
started out as simple POCO types and were decorated with the [Serializable]
attribute. Somewhere a long the lines one of our developers changes up one
of the base classes to also include the [DataContract] attributes (and
[DataMember] etc). The serializer code was changed over to use the
DataContractSerializer in conjunction with a MemoryStream and XmlTextWriter
to retrieve a string which could be passed to a third party. With the
DataContractSerializer changes made in SP1, the [DataContract] attribute is
no longer needed in order to serialize "simple" objects, so again one of our
developers decided to remove "most" of the [Serializable] attributes which
competely clobbered everything pending in the third party system. What
appears to have been happening is when the [DataContract] and [Serializable]
classes were serialized via the DataContractSerializer, the base class had
all public properties serialized (using the public property's names) and all
the individual objects (decorated with the [Serializable] attribute) within
a collection had their name serialized correctly but all of the other values
which were serializer were the private member variables behind the public
properties of the classed marked as [Serializable]. When I stripped off the
[DataContract] and [Serializable] attributes on everything and ran though
the same DataContractSerializer code, everything serialized as expected
using only the public properties (and the appropriate names). One major
problem I have with the DataContractSerializer is when you try to
deserialize from the first example using objects from the second example, no
Exceptions are thown at all. The objects are created as shells and only the
[DataMember] decorated values are populated which means the rest of the data
was dumped/lost in deserialization. Now most of the documentation out on
the web is from everyone using the original functionality (and most haven't
updated it with the new details) so it's a little confusing, but my
assumption is that which using mixed attributes on objects (i.e.
[DataContract] and [Serializable] that when the DataContractSerializer hits
the [Serializable] objects is grabs the private data instead of the public
data. This seams odd to me as I would expect it to serialize everything
both public and private if it was going to grab the private data, but this
is not the case. I have no idea why the items in the collection have their
names serialized correctly. My guess would be maybe its picking up the
BaseObj's [DataContract] attribute somehow. Can someone confirm any of this
or point me in the right direction to get the DataContractSerializer to
operate on the public properties instead of the private members when dealing
with a mixed [DataContract], [Serializable] bag of objects?
Objects
======================
[DataContract]
public class BaseObj
{
private bool _HasChanges;
private bool _IsNew;
[DataMember]
public bool HasChanges
{
get {return _HasChanges;}
set {_HasChanges = value;}
}
[DataMember]
public bool IsNew
{
get {return _IsNew;}
set {_IsNew = value;}
}
}
[Serializable]
public class RootObj : BaseObj
{
private int _key;
private string _name;
private ObservableCollection<Widget> _widgets;
public int Key
{
get {return _key;}
set {_key= value;}
}
public int Name
{
get {return _name;}
set {_name= value;}
}
public ObservableCollection<Widget> Widgets
{
get
{
if (_widgets == null}
_widgets = new ObservableCollection<Widget>();
return _widgets;
}
set {_widgets= value;}
}
}
[Serializable]
public class Widget: BaseObj
{
private int _key;
private DateTime _Date;
private ObservableCollection<Widget> _widgets;
public int Key
{
get {return _key;}
set {_key= value;}
}
public DateTime Date
{
get {return _Date;}
set {_Date= value;}
}
}
Serialized String Output
======================
<RootObj>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>12345</_key>
<_name>TestName</_name>
<_widgets>
<Widget>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>1</_key>
<_Date>2009-12-1 1:00:00</_Date>
<Widget>
<Widget>
<HasChanges>False</HasChanges>
<IsNew>True</IsNew>
<_key>2</_key>
<_Date>2009-11-15 1:00:00</_Date>
<Widget>
</_widgets>
</RootObj>