XmlSerializer differs between .NET 3.5 & CF.NET 3.5 - c#

I've a library that turns under CF.NET & .NET but serialization differs between both. As a result, a XML file generated under CF.NET isn't readable under .NET, and that is a big problem for me !
Here the code sample :
[Serializable, XmlRoot("config")]
public sealed class RemoteHost : IEquatable<RemoteHost>
{
// ...
}
public class Program
{
public static void Main()
{
RemoteHost host = new RemoteHost("A");
List<RemoteHost> hosts = new List<RemoteHost>();
hosts.Add(host);
XmlSerializer ser = new XmlSerializer(typeof(List<RemoteHost>));
ser.Serialize(Console.Out, hosts);
}
}
CF.NET xml :
<?xml version="1.0"?>
<ArrayOfConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<config Name="A">
</config>
</ArrayOfConfig>
.NET xml
<?xml version="1.0" encoding="ibm850"?>
<ArrayOfRemoteHost xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<RemoteHost Name="A">
</RemoteHost>
</ArrayOfRemoteHost>
How can I modify my program in order to generate the same XML ?

It looks like a bug processing the root name, indeed. As a workaround: take control of the root manually:
[XmlRoot("foo")]
public class MyRoot {
[XmlElement("bar")]
public List<RemoteHost> Hosts {get;set;}
}
This should serialize as
<foo><bar>...</bar>...</foo>
on either platform. Substitute foo and bar for your preferred names.
(personally, I'd be using binary output, though ;p)

Related

Adding a new field to a class to be serialized

To be able to serialize and deserialize a XML I had designed like this:
<?xml version="1.0" encoding="utf-8"?>
<DbConnections xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DbConnectionInfo>
<ServerName>SQLServer2k8</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>SQLServer2k8R2</ServerName>
</DbConnectionInfo>
</DbConnections>
I had written two classes like this below:
public class DbConnectionInfo
{
public string ServerName { get; set; }
}
and
[Serializable]
[XmlRoot("DbConnections")]
public class DbConnections: List<DbConnectionInfo>
{
//...
}
Now I want to expand my XML form and add one more field like this but is there is a way to design my class in a way that I don' have to REPEAT it in every XML tag? like this:
<?xml version="1.0" encoding="utf-8"?>
<DbConnections xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DbConnectionInfo>
<ServerName>SQLServer2k8</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>SQLServer2k8R2</ServerName>
</DbConnectionInfo>
<UseWindowsAuthentication>Yes</UseWindowsAuthentication>
</DbConnections>
So I just really added that one line to previous XML:
But my question is how should I modify my classes to add this? And is it even possible or a correct design?
<UseWindowsAuthentication>Yes</UseWindowsAuthentication>
Maybe something like this
[Serializable]
[XmlRoot("DbConnections")]
public class DbConnections
{
List<DbConnectionInfo> DbConnectionInfos;
Boolean UseWindowsAuthentication;
}
Edited to add: if you do not want nested elements, decorate your class as so
public class DbConnections
{
[XmlElement("DbConnectionInfo")]
public List<DbConnectionInfo> DbConnectionInfos;
public Boolean UseWindowsAuthentication;
}
I tested this and the following xml was serialized
XmlSerializer serializer = new XmlSerializer(typeof(DbConnections));
string xml;
using (StringWriter textWriter = new StringWriter())
{
serializer.Serialize(textWriter, oDbConnections);
xml = textWriter.ToString();
}
<?xml version="1.0" encoding="utf-16"?>
<DbConnections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbConnectionInfo>
<ServerName>test</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>test 2</ServerName>
</DbConnectionInfo>
<UseWindowsAuthentication>true</UseWindowsAuthentication>
</DbConnections>
Here is a link to more info on decorating for xml serialization

Deserialize using DataContractSerializer

I am trying to Deserialize an xml file that looks like the following
<?xml version="1.0"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication6">
<values>
<String>Value 1</String>
<String>Value 2</String>
</values>
</Test>
to an object that is this
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/ConsoleApplication6")]
public class Test
{
[DataMember(Name = "values")]
public String[] values;
}
with
var ds = new DataContractSerializer(typeof(Test));
using (Stream stream1 = File.OpenRead(#"C:\Projects\test1.xml"))
{
Test rr = (Test)ds.ReadObject(stream1);
}
However none of the values are deserializing. I just see and empty array in Test rr. Could you please tell what I am doing wrong. Thanks in advance.
If you need fine control of the XML that is emitted when serializing, you should not use DataContractSerializer. It is has very limited flexibility. You would be better off using XmlSerializer, which has liimtitations as well, but is much more flexible than DataContractSerializer.
That being said, here is how you can do what you want with DataContractSerializer.
Change the default namespace on your xml to use the one that DataContractSerializeruses by default.
<?xml version="1.0"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
<values>
<String>Value 1</String>
<String>Value 2</String>
</values>
</Test>
Instead of using string[] create your own custom type that derives from List<string>. This must be done solely for the purpose of having something to hang CollectionDataContractAttribute on. CollectionDataContractAttribute is what will let you specify the name of the elements inside <values>.
[DataContract]
public class Test
{
[DataMember(Name = "values")]
public TestValues values;
}
[CollectionDataContract(ItemName = "String")]
public class TestValues : List<string> { }
The DataContractSerializer has its own rules for XML and cannot support all XML forms. I suggest using the XmlSerializer.
Use this definition
[XmlClass(Namespace = "http://schemas.datacontract.org/2004/07/ConsoleApplication6")]
public class Test
{
[XmlArray("values")]
[XmlArrayItem("String")]
public String[] values;
}

C# Changing the element names of items in a list when serializing/deserializing XML

I have a class defined as below:
[XmlRoot("ClassName")]
public class ClassName_0
{
//stuff...
}
I then create a list of ClassName_0 like such:
var myListInstance= new List<ClassName_0>();
This is the code I use to serialize:
var ser = new XmlSerializer(typeof(List<ClassName_0>));
ser.Serialize(aWriterStream, myListInstance);
This is the code I use to deserialize:
var ser = new XmlSerializer(typeof(List<ClassName_0>));
var wrapper = ser.Deserialize(new StringReader(xml));
If I serialize it to xml, the resulting xml looks like below:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClassName_0 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ClassName_0>
<stuff></stuff>
</ClassName_0>
<ClassName_0>
<stuff></stuff>
</ClassName_0>
</ArrayOfClassName_0>
Is there a way to serialize and be able to deserialize the below from/to a list of ClassName_0?
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClassName xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ClassName>
<stuff></stuff>
</ClassName>
<ClassName>
<stuff></stuff>
</ClassName>
</ArrayOfClassName>
Thanks!
In your example ClassName isn't the real root.
The real root is your list. So you have to mark the list as the root element.
Your class is just an XmlElement.
try this :
XmlType(TypeName="ClassName")]
public class ClassName_0
{
//stuff...
}
Worked it out, finally, with the help of Jan Peter. XmlRoot was the wrong attribute to put on the class. It was supposed to be XmlType. With XmlType the desired effect is achieved.
You make a root of document tree and this root will contain list of any object.
[XmlRootAttribute("myDocument")]
public class myDocument
{
[XmlArrayAttribute]
publict ClassName[] ArrayOfClassName {get;set;}
}
[XmlType(TypeName="ClassName")]
public class ClassName
{
public string stuff {get;set;}
}

Create XSD for hierarchical data

I want to export objects to XML and create XSD. following are the base classes
class Owner
{
private int id;
private string name;
private List<Car> cars;
private int age;
}
class CarTemplate
{
private int drive;
private double engineCc;
}
class Car
{
private int id;
private string name;
private double cost;
private CarTemplate template;
}
Following is the modified structure that I want to export to XML and create XSD out of it
class ExportedOwner
{
private int id;
private string name;
private List<Car> cars;
}
class ExportedCar
{
private string name;
private double cost;
private CarTemplate template;
}
The structure of XML should be in following format
<?xml version="1.0" encoding="utf-8" ?>
<Owner>
<id>1</id>
<Name>John</Name>
<Age>49</Age>
<Cars>
<Car>
<id>1</id>
<Name>Merc Class C</Name>
<CarTemplate>
<drive>2</drive>
<engineCc>2500</engineCc>
</CarTemplate>
</Car>
<Car>
<id>2</id>
<Name>Merc Class M</Name>
<CarTemplate>
<drive>4</drive>
<engineCc>2900</engineCc>
</CarTemplate>
</Car>
</Cars>
</Owner>
How can I create XSD for the XML format. I want XSD for importing the XML file back into the appication.
Use XSD.EXE for generating your XSD: it's a standard .NET Framework tool. See http://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx to see how it is used.
There's 2 distinct questions to answer here...
First, how to export your objects to an XML file. There are many ways to do this in .NET. The two most common (XmlSerializer and DataContractSerializer) are compared side by side in this blog post.
The second part of your question is a little more broad. Generating an xsd schema from an existing XML file is not an exact science, but there are tools out there that can infer (or guess) a schema from an XML file. There are various little tools which can do this for you - it might be worth trying a few of them and seeing which one gives you best results. As always, google is your good friend :)
You can use the standard XML serializer for this (with xsd.exe). You would need to use the KnownTypeAttribute on the base class in order for the deserialized to know how to rehydrate the structure.
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.knowntypeattribute.aspx
If you want to generate the XML out of your classes dynamically, you could use System.Reflection
For example:
Type type = typeof(ExportedOwner);
var propertyinfos = type.GetProperties(); // gives you a list of all properties of ExportedOwner
And then generate your XML according to your specification with your favourite XMl Writer.

XML Deserialization with C# .NET 3.5

I Have this XML File
<?xml version="1.0" standalone="yes"?>
<Root>
<Object>
<referenceName>People</referenceName>
<query>select * from people</query>
</Object>
<Object>
<referenceName>Countries</referenceName>
<query>select * from countries</query>
</Object>
</Root>
I need to convert into an object with C#.
I got confused how to do it.
Kindly note that I can have alot of objects in the xml file.
I know that i have to use an [XMLArray......
Thanks
The simplest trick here is at the VS command line:
xsd example.xml
xsd example.xsd /classes
Et voila; one example.cs file with example C# that shows how to get that xml from .NET objects via XmlSerializer.
In this case, I expect the following would work:
public class Root
{
[XmlElement("Object")]
public List<SomeOtherObject> Objects { get; set; }
}
public class SomeOtherObject
{
[XmlElement("referenceName")]
public string Name { get; set; }
[XmlElement("query")]
public string Query { get; set; }
}
update: validated it; yup, it works...
XmlSerializer ser = new XmlSerializer(typeof(Root));
using (XmlReader reader = XmlReader.Create(
new StringReader(xml)))
{
var obj = (Root)ser.Deserialize(reader);
// use obj
}
Use the xsd.exe tool to generate an initial set of classes to start with. Once you have those, tweak if needed (post the generated classes) and use System.Xml.Serialization.XmlSerializer to deserialize back into the runtime object.

Categories

Resources