Anders
Anders

Reputation: 580

How to debug XML deserialization?

I was wondering if you had any tips on how I can debug the below XML deserialization? I cannot get it to work. The deserializer basically creates the summon and slash instances, but all their properties are empty. The relevant classes to are shown below.


SkillCollection class with Deserializer:

[DataContract(Name = "Skills", Namespace = "")]
public class SkillCollection
{

[DataMember(Name = "Slash")]
public Skill Slash { get; set; }

[DataMember(Name = "Summon")]
public Skill Summon { get; set; }

public static object Deser(string path, Type toType)
{
    var s = new DataContractSerializer(toType);
    using (FileStream fs = File.Open(path, FileMode.Open))
    {
        object s2 = s.ReadObject(fs);
        if (s2 == null)
            Console.WriteLine(@"  Deserialized object is null");
        else
            Console.WriteLine(@"  Deserialized type: {0}", s2.GetType());
        return s2;
    }
}

It is called from another class through property Skills:

Skills = (SkillCollection)SkillCollection.Deser(
            Path.Combine(path, "Skills.xml"), 
            typeof(SkillCollection));

Skill class:

public class Skill
{
    //Cast: time it takes to cast it
    [DataMember(Name = "Cast")]
    public float Cast { get; set; }

    //ReCast: cooldown period before player can cast it again
    [DataMember(Name = "ReCast")]
    public float ReCast { get; set; }

    [DataMember(Name = "MPCost")]
    public int MpCost { get; set; }

    public Timer Timer { get; private set; }
    public bool Ready { get; set; }

    public Skill()
    {
        Ready = true;

        Timer = new Timer { Interval = ReCast + 500, AutoReset = false };
        Timer.Elapsed += OnTimedEvent;
    }

    //Runs when recast is up
    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Ready = true;
    }
}

XML File:

<Skills>
  <Slash>
    <Cast>0.00</Cast>
    <ReCast>60.00</ReCast>
    <MPCost>0</MPCost>
  </Slash>
  <Summon>
    <Cast>5.98</Cast>
    <ReCast>2.49</ReCast>
    <MPCost>0</MPCost>
  </Summon>
</Skills>

Just so there is no confusion, my goal is to run the deserializer, and then have the SkillCollection class contain the two instances of Skill (Slash and Summon), and be able to access them separately through their properties.

Thanks for any help / tips with debugging this.

Upvotes: 3

Views: 6690

Answers (1)

Magnus
Magnus

Reputation: 7829

Anders,

I recently did a similar task. Looking at your code it seems you set DataContract Name and Namespace wrong. Both above the Skill class and the SkillCollection class you need to specify: [DataContract(Name = "Skills", Namespace = "")]. This is critical for the serializer to be "allowed" to enter the Properties. Keep in mind that just setting it above the SkillCollection class will not be enough.

EDIT: I initially thought you could leave out Namespace, but you cannot. It has to be set to either Namespace="", in the case you do not specify a namespace in the XML, or to whatever you specify the namespace to be, in the case you do specify it.

Also, a way to debug it is to change the Deser method to this:

    public static object Deserialize(string path, Type toType)
    {
        using (var sr = new FileStream(path, FileMode.Open))
        {
            SkillCollection p = null;
            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(sr, new XmlDictionaryReaderQuotas());
            var serializer = new DataContractSerializer(toType);

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        if (serializer.IsStartObject(reader))
                        {
                            Console.WriteLine(@"Found the element");
                            p = (SkillCollection)serializer.ReadObject(reader);
                            Console.WriteLine("{0} {1}    id:{2}",
                                p.Slash.ToString(), p.Summon.ToString());
                        }
                        Console.WriteLine(reader.Name);
                        break;
                }
            }

            return p;
        }
    }

Upvotes: 1

Related Questions