DataContractSerializer with mixed bag of DataContract and Serializable attributes

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>
 
T

Techno_Dex

I have found my answer. It appears that the DataContractSerializer will
which presented with a [Serializable] attribute will fall back to using the
..NET Remoting style of serialization which is to only include the fields
when serialzing instead of using the public properties/fields like the
[DataContract]/[DataMember] attributes do. It would be nice if MSDN would
update their documentation to include these important details.

http://www.pluralsight.com/community/blogs/aaron/archive/2008/05/13/50934.aspx


Techno_Dex said:
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>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top