Serialization not working

R

RobinS

I want to serialize a class that I am using to retain some information the
user types into a screen. I have 3 questions.

1) I serialized it as XML to start with. This works, but how do I serialize
the strings so that they are not messed up if they have XML in them, or
control characters? Is there a way to do that in XML, or do I have to use
BinaryFormatters?

2) So I tried using a binary formatter, and it won't serialize/deserialize
the darn thing. It doesn't look like rocket science, but apparently I'm
missing something. Simplified example below.

3) If I use a binary formatter (or an XML one for that matter), what
happens if/when I add a new property to my class? Do I need to account for
that somehow?

I'm posting all of the code with the three test cases (one uses a memory
stream just for grins; it doesn't work either). It's about 130 lines of
code. Hope this isn't too much to post. Hopefully the intendation will come
across right.


//===================================================================
using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
using System.IO;


namespace TestFruitLoopsTiny
{
[Serializable()]
public class BusinessCardData
{

[NonSerialized()]
private string _NameData;
public string NameData
{
get { return _NameData; }
set { _NameData = value; }
}

[NonSerialized()]
private string _CompanyData;
public string CompanyData
{
get { return _CompanyData; }
set { _CompanyData = value; }
}

public BusinessCardData()
{
SetDefaults();
}

public void SetDefaults()
{
this.NameData = string.Empty;
this.CompanyData = string.Empty;
}

public void TestBinary()
{
//Write it
using (FileStream fs
= new FileStream("D:\\test.dat", FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.File));
bf.Serialize(fs, this);
OutputData("Original data (binary)", this);
}
//Read it
if (System.IO.File.Exists("D:\\test.dat"))
{
using (FileStream fs
= new FileStream("D:\\test.dat", FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.File));
BusinessCardData bcd = (BusinessCardData)bf.Deserialize(fs);
OutputData("After reading it back in (binary) ", bcd);
}
}
}

public void TestXML()
{
XmlSerializer xs = new XmlSerializer(typeof(BusinessCardData));
using (FileStream fs = new FileStream("D:\\test.dat",
FileMode.Create))
{
xs.Serialize(fs, this);
OutputData("Original data (XML)", this);
}
//read it back in
BusinessCardData bcd;
using (FileStream fs = new FileStream("D:\\test.dat", FileMode.Open))
{
bcd = (BusinessCardData)xs.Deserialize(fs);
}
OutputData("After reading it back in (XML)", bcd);
}

public void TestMemory()
{
using (MemoryStream ms = new MemoryStream(200))
{
OutputData("OriginalData (memory)", this);
BinaryFormatter bf = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.Clone));
bf.Serialize(ms, this);
//read it back in
ms.Seek(0, SeekOrigin.Begin);
BusinessCardData abc = (BusinessCardData)bf.Deserialize(ms);
OutputData("After reading it back in (memory)", abc);
}
}

private static void OutputData(string caption,
BusinessCardData bcd)
{
Console.WriteLine(caption);
Console.WriteLine(" Name = {0}, Company = {1}",
bcd.NameData, bcd.CompanyData);
}

}
}

//===================================================================
//****TEST ROUTINE***
static void Test()
{
BusinessCardData bcd = new BusinessCardData();
bcd.CompanyData = "Apple";
bcd.NameData = "Robin";
bcd.TestBinary();

bcd.CompanyData = "Apple";
bcd.NameData = "Robin";
bcd.TestXML();

bcd.CompanyData = "Apple";
bcd.NameData = "Robin";
bcd.TestMemory();

Console.ReadLine("Press any key to return");

}
//===================================================================

I'm sure I'm doing something stupid, or stupidly NOT doing something.

I'd appreciate any help you can provide.

Thanks,
Robin S.
 
J

Jon Skeet [C# MVP]

RobinS said:
I want to serialize a class that I am using to retain some information the
user types into a screen. I have 3 questions.

1) I serialized it as XML to start with. This works, but how do I serialize
the strings so that they are not messed up if they have XML in them, or
control characters? Is there a way to do that in XML, or do I have to use
BinaryFormatters?

If they contain XML themselves, that's fine. If they contain control
characters which aren't allowed in XML, serialization will produce an
invalid XML file and deserialization will fail.
2) So I tried using a binary formatter, and it won't serialize/deserialize
the darn thing. It doesn't look like rocket science, but apparently I'm
missing something. Simplified example below.

I *believe* that BinaryFormatter uses fields rather than properties for
serialization. You've specified that the fields shouldn't be
serialized, so you don't get any useful information out.
3) If I use a binary formatter (or an XML one for that matter), what
happens if/when I add a new property to my class? Do I need to account for
that somehow?

With binary formatters, if you add a new field (or remove an old one) I
believe you have to go through significant hoops to get cross-version
serialization to work.

I *believe* the XML formatter will ignore any extra properties it
doesn't understand in the XML it reads for deserialization, and won't
complain if not all the properties are specified.

You may have noticed a large amount of "belief" statements in here -
I'm far from an expert on serialization. These are just my beliefs,
mostly based on experimentation with your test app.
 
R

RobinS

Comments below...

Jon Skeet said:
If they contain XML themselves, that's fine. If they contain control
characters which aren't allowed in XML, serialization will produce an
invalid XML file and deserialization will fail.

**********************

So what about carriage returns or if they have some kind of tags in them?
Will either of those cases cause me problems? My boss said something about
being able to wrap the strings in some kind of brackets so XML will know
everything inside the brackets is text, even if it's some kind of XML-y
script. I mean, if they put in something like </NameData>, how could it
work?

**********************
I *believe* that BinaryFormatter uses fields rather than properties for
serialization. You've specified that the fields shouldn't be
serialized, so you don't get any useful information out.

**********************
Arggghhhhhh!!!!! You're right. I remove the attributes for not serializing,
and it worked. One of the examples I looked at had all of the private
fields marked with attributes, so I assume they would be serialized (in
XML) if I didn't mark them appropriately.
**********************
With binary formatters, if you add a new field (or remove an old one) I
believe you have to go through significant hoops to get cross-version
serialization to work.

I *believe* the XML formatter will ignore any extra properties it
doesn't understand in the XML it reads for deserialization, and won't
complain if not all the properties are specified.

**********************
You're right, the XML formatter does appear to handle extra properties.
I saved the file, added a new property, and read the file back in, and it
works fine. I would be more than happy working with XML if I can figure out
what to do about the carriage-returns and any kind of funky characters
they put into the textboxes.

Also, when I read it back in, it doesn't "display" the carriage-returns
in the textbox, but they are there. I'm taking the entries and writing them
to
a graphics surface using DrawString, and the carriage returns are showing
up in the output. Then later I'm reading the XML back in and putting it
back in the textboxes for the user to edit. The textbox has "AcceptsReturn"
set to true. Do I need to check the string for carriage-returns and split
it into the lines[] property of the textbox?

**********************
You may have noticed a large amount of "belief" statements in here -
I'm far from an expert on serialization. These are just my beliefs,
mostly based on experimentation with your test app.


Reminds me "This I Believe", on NPR. "This I believe -- that XML
serialization
is easy if you do it right!"

Thanks for the comments and help, and to anyone else who chimes in.

Robin S.
 
M

Marc Gravell

Re xml characters in the string, they will be escaped according to the
rules of xml - usually as &lt; and &gt; etc. Note that for a high-
density string of xml (lots of small tags) this could cause non-
trivial bloat. Carriage return is legal xml, but note the whitespace
rules in xml. But the serialization authors have considered most of
these things - it should just work.

Re adding fields (BinarySerializer) - look at Version Tolerant
Serlialization: http://msdn2.microsoft.com/en-us/library/ms229752.aspx

Re ading properties (XmlSerializer) - one other thing that might be of
interest is DataContractSerializer; apart from offering more
flexibility than the older XmlSerializer, this also offers simple
forward (and round-trip) compatibility.
http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx

Marc
 
D

Didier Bolf

Marc Gravell said:
Re xml characters in the string, they will be escaped according to the
rules of xml - usually as &lt; and &gt; etc. Note that for a high-

hello Marc
you can avoid &lt; and &gt; by implementing IXmlSerializable and use
WriteRaw and ReadOuterXml functions :

public void WriteXml(XmlWriter writer)
{
...
writer.WriteRaw(myXmlAttr);
...
}
public void ReadXml(XmlReader reader)
{
...
myXmlAttr = reader.ReadOuterXml();
...
}


Didier
 
R

RobinS

Thanks to all who replied. It was a lot of really useful info!

Robin S.
------------------------------
 

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