Aleksandras Dzierkac Aleksandras Dzierkac - 18 days ago 7
C# Question

XML deserialization returns an empty object[Solved]

Hello I have a problem here about deserialization. I have a xml file that I need to deserialize into a class that I get from a Service refrence. I know how to deserialize a xml file, but when I try to deserialize this file I get a empty class object. And I don't understand why is it doing that?
The xml files content looks like this:

<?xml version="1.0" encoding="UTF-8" ?><iVAZFile xmlns="http://www.v.lt/c/i/iv">
<FileDescription>
<FileVersion>i1.3.3</FileVersion>
<FileDateCreated>2016-11-07T12:28:32</FileDateCreated>
<SoftwareCompanyName>otechnika&quot;</SoftwareCompanyName>
<SoftwareName>Eita</SoftwareName>
<SoftwareVersion>2016.9</SoftwareVersion>
<CreatorRegistrationNumber>123060356</CreatorRegistrationNumber>
</FileDescription>
</iVAZFile>


The class looks like this:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1590.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.v.lt/c/i/iv")]
public partial class FileDescription : object, System.ComponentModel.INotifyPropertyChanged {

private string fileVersionField;

private System.DateTime fileDateCreatedField;

private string softwareCompanyNameField;

private string softwareNameField;

private string softwareVersionField;

private ulong creatorRegistrationNumberField;

public FileDescription() {
this.fileVersionField = "iVAZ1.3.3";
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public string FileVersion {
get {
return this.fileVersionField;
}
set {
this.fileVersionField = value;
this.RaisePropertyChanged("FileVersion");
}
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=1)]
public System.DateTime FileDateCreated {
get {
return this.fileDateCreatedField;
}
set {
this.fileDateCreatedField = value;
this.RaisePropertyChanged("FileDateCreated");
}
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public string SoftwareCompanyName {
get {
return this.softwareCompanyNameField;
}
set {
this.softwareCompanyNameField = value;
this.RaisePropertyChanged("SoftwareCompanyName");
}
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string SoftwareName {
get {
return this.softwareNameField;
}
set {
this.softwareNameField = value;
this.RaisePropertyChanged("SoftwareName");
}
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=4)]
public string SoftwareVersion {
get {
return this.softwareVersionField;
}
set {
this.softwareVersionField = value;
this.RaisePropertyChanged("SoftwareVersion");
}
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=5)]
public ulong CreatorRegistrationNumber {
get {
return this.creatorRegistrationNumberField;
}
set {
this.creatorRegistrationNumberField = value;
this.RaisePropertyChanged("CreatorRegistrationNumber");
}
}

public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}


And the method that I use to populate the class:

using (MemoryStream memoryStream = new MemoryStream())
{
using (BinaryWriter binWriter = new BinaryWriter(memoryStream, Encoding.UTF8))
{
string filep = File.ReadAllText("test.xml");
binWriter.Write(filep);
memoryStream.Seek(2, SeekOrigin.Begin);
using (StreamReader streamReader = new StreamReader(memoryStream))
{
using (XmlReader reader = XmlReader.Create(streamReader))
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "FileDescription";
xRoot.IsNullable = false;
XmlSerializer serializer = new XmlSerializer(typeof(FileDescription),xRoot);
FileDescription dsc = new FileDescription();
dsc=(FileDescription)serializer.Deserialize(reader);
}
}
}
}


A few additional comment to say what I also tried:


  1. I made my own class that looked the same as the one from the service reference and added a new parameter
    [XmlRoot(ElementName="FileDescription"),XmlType("FileDescription")]

    then the deserilization worked on my class.

  2. Tried adding values by hand without deserilization that worked fine as well so there's no problem with the service code.

  3. Also when I'm deserializing the xml I remove
    <iVAZFile xmlns="http://www.v.lt/c/i/iv">
    and
    </iVAZFIle>
    because when deserializing it will throw and exception was not expecting .



And lastly a few words I cannot change the service reference class and I need to use that class for later so I cannot make my own.

Edit: The problem is solved thanks to Charles Mager. The problem was I had to add the namespace to every value in my xml so it would have to look like this:

<FileDescription>
<FileVersion xmlns="http://www.v.lt/c/i/iv">i1.3.3</FileVersion>
<FileDateCreated xmlns="http://www.v.lt/c/i/iv">2016-11-07T12:28:32</FileDateCreated>
<SoftwareCompanyName xmlns="http://www.v.lt/c/i/iv">otechnika&quot;</SoftwareCompanyName>
<SoftwareName xmlns="http://www.v.lt/c/i/iv">Eita</SoftwareName>
<SoftwareVersion xmlns="http://www.v.lt/c/i/iv">2016.9</SoftwareVersion>
<CreatorRegistrationNumber xmlns="http://www.v.lt/c/i/iv">123060356</CreatorRegistrationNumber>
</FileDescription>


Now it works fine thanks for the help.

Answer

The difference is the namespace - per the XmlType attribute on your FileDescription class, the namespace is http://www.v.lt/c/i/iv. This applies to all child elements of the FileDescription. The root namespace is whatever you configure via your XmlRootAttribute or by the constructor that takes a default namespace.

As I suggested, the easiest way to debug this sort of issue is to do the reverse - serialise an object and see what it looks like. As you can see in this fiddle the output at present would look like this. This is why you're not getting any error (as the root class matches), but all the child elements in the XML you're deserialising are in the wrong namespace.

<FileDescription>
  <FileVersion xmlns="http://www.v.lt/c/i/iv">iVAZ1.3.3</FileVersion>
  <FileDateCreated xmlns="http://www.v.lt/c/i/iv">0001-01-01T00:00:00</FileDateCreated>
  <CreatorRegistrationNumber xmlns="http://www.v.lt/c/i/iv">0</CreatorRegistrationNumber>
</FileDescription>

If you specify the same namespace for the root as in this fiddle, the output looks like this:

<FileDescription xmlns="http://www.v.lt/c/i/iv">
  <FileVersion>iVAZ1.3.3</FileVersion>
  <FileDateCreated>0001-01-01T00:00:00</FileDateCreated>
  <CreatorRegistrationNumber>0</CreatorRegistrationNumber>
</FileDescription>

You need to keep the namespace in your amended document. You can see this works in this fiddle.

Comments