What I've learned is that if I explicitly case my reference to the actual
type it is then things will work fine.
If you change this line:
byte[] serializedData = SerializationUtils.Serialize(db);
To:
byte[] serializedData = SerializationUtils.Serialize(db as Doc100Entry);
It will work.
I googled and read some more about the XmlInclude attribute, so I tried it
out by adding this above DocEntryBase:
[XmlInclude(typeof(Doc100Entry))]
It will serialize fine with that attribute (good!) but when I try to
deserialize it I get this exception:
"<DocEntryBase xmlns=''> was not expected."
Here is a (semi) complete example that shows the problem:
<code>
// Argh.cs
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Text;
namespace ImageConversion
{
public class BusinessEntity
{
private string _id;
public string ID
{
get { return _id; }
set { _id = value; }
}
}
[Serializable]
public abstract class DocEntryBase : BusinessEntity
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
[Serializable]
public abstract class Doc100EntryBase : DocEntryBase
{
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}
[Serializable]
public class Doc100Entry : Doc100EntryBase
{
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
}
}
// (snipped from Form.cs)
private void button6_Click(object sender, EventArgs e)
{
try
{
Doc100Entry d = new Doc100Entry();
d.Age = 333;
d.ID = "argh!";
d.LastName = "Klett";
d.Name = "Steve Klett";
DocEntryBase db = d;
byte[] serializedData = SerializationUtils.Serialize(db);
FileUtils.WriteBytesToFile(@"c:\xmlTest.xml", serializedData);
serializedData = null;
serializedData = FileUtils.ReadWholeFileBytes(@"c:\xmlTest.xml");
d = null;
d = SerializationUtils.Deserialize<Doc100Entry,
DocEntryBase>(serializedData);
}
catch (Exception ee)
{
Console.WriteLine(ee.ToString());
}
}
// SerializationUtils.cs
namespace PMD.Library
{
public static class SerializationUtils
{
public static byte[] Serialize<TType/*, TBaseType*/>(TType entity)
where TType : class/*, TBaseType*/
{
byte[] data = null;
using (MemoryStream memStream = new MemoryStream())
{
XmlSerializer xs = new XmlSerializer(typeof(TType));
XmlTextWriter xmltr = new XmlTextWriter(memStream,
Encoding.ASCII);
xmltr.Formatting = Formatting.Indented;
xs.Serialize(xmltr, entity);
data = (xmltr.BaseStream as MemoryStream).ToArray();
}
return data;
}
public static TType Deserialize<TType, TBaseType>(byte[] data)
where TType : class, TBaseType
{
XmlSerializer serializer = new XmlSerializer(typeof(TType));
return serializer.Deserialize(new MemoryStream(data)) as TType;
}
}
}
// FileUtils.cs
using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
using System.Text;
namespace PMD.Library
{
public static class FileUtils
{
public static byte[] ReadWholeStream(Stream stream)
{
byte[] buffer = new byte[stream.Length];
int offset = 0;
int remaining = (int)stream.Length;
while (remaining > 0)
{
int read = stream.Read(buffer, offset, remaining);
if (read <= 0)
{
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes
left to read", remaining));
}
remaining -= read;
offset += read;
}
return buffer;
}
public static byte[] ReadWholeFileBytes(string filename)
{
if(string.IsNullOrEmpty(filename))
{
throw new ApplicationException("filename must be a valid
path to a file and not null");
}
if(File.Exists(filename) == false)
{
throw new FileNotFoundException(string.Format("Failed
finding file {0}", filename));
}
using (Stream stream = new FileStream(filename, FileMode.Open))
{
return ReadWholeStream(stream);
}
}
/// <summary>
/// Saves the byte[] data to a file on the file system.
/// If the file or path don't exist they will be created.
/// </summary>
/// <param name="filename">Name of the file to be saved.</param>
/// <param name="data">Data to save to the file.</param>
public static void WriteBytesToFile(string filename, byte[] data)
{
// Check if the target directory exists, if not create it.
string path = Path.GetDirectoryName(filename);
if(Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
using(Stream stream = new FileStream(filename,
FileMode.OpenOrCreate, FileAccess.Write))
{
stream.Write(data, 0, data.Length);
}
}
}
}
</code>
I'm lost at this point ;0|
Steve K. said:
I'm getting an error deserializing some XML and it really doesn't make
sense to me.
Here are my classes that I'm serializing/deserializing:
<code>
public abstract class BusinessEntity : INotifyPropertyChanged
{
// only has one protected method, no need to serialize
}
[Serializable]
[XmlInclude(typeof(Doc100Entry))]
public class DocEntryBase : BusinessEntity
{
}
[Serializable]
public abstract class Doc100EntryBase : DocEntryBase
{
}
[Serializable]
public class Doc100Entry : Doc100EntryBase
{
}
</code>
Here is a snippet of the XML
<code>
<?xml version="1.0" encoding="us-ascii"?>
<DocEntryBase xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xsi:type="Doc100Entry">
(snipped...)
</DocEntryBase>
</code>
I'm getting the following exception when deserializing an instance
Doc100Entry:
"<DocEntryBase xmlns=''> was not expected."
I made a change to DocEntryBase that started this whole mess, it used to
be an abstract class (and worked fine). I removed the abstract modifier
because of a design change and I've had serialization problems ever since.
Anyone see an obvious problem with my setup here?