I am converting my working XML serialization so that the model classes inherit from abstract base classes (to allow for future use of different serial formats).
My serialization as-is is working fine but when I switch to using models derived from a base class I get all kinds of exceptions so I'm unsure of how to proceed.
My class base class is:
namespace Data
{
public abstract class Configuration
{
public abstract string Schema { get; set; }
public abstract Command[] Commands { get; set; }
}
public abstract class Command
{
public abstract string Name { get; set; }
}
}
My derived concrete class (the class that is working just fine before it was derived) is then in a child namespace:
namespace Data.Xml
{
[Serializable()]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Configuration : Data.Configuration
{
[XmlAttribute("noNamespaceSchemaLocation",
Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace)]
public override string Schema { get; set; }
[XmlArrayItem("Command", IsNullable = false)]
public override Data.Command[] Commands { get; set; }
}
[Serializable()]
public class Command : Data.Command
{
public override string Name { get; set; }
}
}
I call the serializer within that child namespace like so:
public override Data.Configuration DeserializeConfig(StreamReader config)
{
var cs = new XmlSerializer(typeof(Configuration),
new Type[] { typeof(Command) });
return (Configuration)ConfigSerializer.Deserialize(ConfigStreamReader);
}
public override string SerializeConfig(Data.Configuration c, Encoding encoding)
{
string Output = null;
var Stream = new MemoryStream();
using (var Writer = new XmlTextWriter(Stream, encoding))
{
Writer.Formatting = Formatting.Indented;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xsi", XmlSchema.InstanceNamespace);
(new XmlSerializer(typeof(Configuration))).Serialize(Writer, c, ns);
Output = encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
The resulting XML should look like:
<?xml version="1.0" encoding="utf-8"?>
<Configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="SomeSchema.xsd">
<Commands>
<Command>
<Name>SomeNameValue</Name>
</Command>
</Commands>
</Configuration>
I am seeing the following exception when attempting to instantiate the serializer (first line in DeserializeConfig()
method above):
InvalidOperationException: Types 'Data.Command' and 'Data.Xml.Command' both use the XML type name, 'Command', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.
I'm not really sure why the serializer is trying to create something from the base class, sure the names are the same, that's kind of the idea of derivation and namespaces etc ... How do I properly mark this up with attributes to have it de/serialize properly?
FYI: I did see several questions already on this, but the answers all seemed specific enough to the askers requirements that I could not work out how to apply the information to this, seemingly simple, scenario.
Update: I figured out how to pass included types into the serializer at instantiation instead of having to annotate the base class so I have removed that part from my question and updated the code. This outdates bruno's suggestion and my response (although the suggested question still does not apply).
Update: I attempted to separate the names in XML namespaces by adding the derived class to a namespace (i.e. adding [XmlElement(Namespace = "http://www.foo.com/data/xml")]
to each property in the derived class) but this made no difference as the serializer still seems to "see" both the base and derived class together and so thinks they're both in that namespace.