0

I am trying to create a re-usable serializer/deserializer for my application, and I am running into an "Object reference not set to an instance of an object" error, and I don't understand why.

Here is my serializer code:

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "ReportAutomation Test Application", IsNullable = false)]
public class ReportSpec{
    [System.Xml.Serialization.XmlElementAttribute("Report")]
    public List<ReportsHolder> ReportsList { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public double Version { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Username { get; set; }
}

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public class ReportsHolder{
    public List<FirstClass> FirstClassReportsList { get; set; }
    public List<SecondClass> SecondClassReportList { get; set; }
}

public class BaseClass{
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string ReportName { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string FilterMode { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Destination { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Format { get; set; }
}

public class FirstClass : BaseClass{
    public string AlertSource { get; set; }

    public bool ShouldSerializeAlertSource(){
        return AlertSource != null;
    }
}

public class SecondClass : BaseClass{
    public int? DeviceID;

    public bool ShouldSerializeDeviceID(){
        return DeviceID != null;
    }
}

Here is where I try to create my XML file:

    private string outputPath = @"C:\temp\ReportAutomationTest.xml";

        private void CreateFile(){
            XmlSerializer serializer = new XmlSerializer(typeof(ReportSpec));
            TextWriter writer = new StreamWriter(outputPath);

            // create the root object
            ReportSpec myReportSpec = new ReportSpec{ Username = "My Name", Version = 4.5 };

            // create the report holder
            ReportsHolder myReportsHolder = new ReportsHolder();

            // create a FirstClass object
            FirstClass myFirstClass = new FirstClass();
            myFirstClass.ReportName = "Base Camp Report";
            myFirstClass.FilterMode = "Container";
            myFirstClass.Destination = "someone@somewhere.com";
            myFirstClass.Format = "PDF";

            myFirstClass.AlertSource = "Base Camp 1";


            // add myFirstClass to the FirstClassList
            myReportsHolder.FirstClassReportsList.Add(myFirstClass);  // <-- Object reference not set to an instance of an object.

            // create another FirstClass object
            FirstClass anotherFirstClass = new FirstClass();
            anotherFirstClass.ReportName = "Satellite Stations Report";
            anotherFirstClass.FilterMode = "Container";
            anotherFirstClass.Destination = @"\\path\on\my\network";
            anotherFirstClass.Format = "DOC";

            anotherFirstClass.AlertSource = "Satellite Station 1";

            // add myFirstClass to the FirstClassList
            myReportsHolder.FirstClassReportsList.Add(anotherFirstClass);


            // create a SecondClass object
            SecondClass mySecondClass = new SecondClass();
            mySecondClass.ReportName = "Device Inventory Report";
            mySecondClass.FilterMode = "Container";
            mySecondClass.Destination = "someone@somewhere.com";
            mySecondClass.Format = "PDF";

            mySecondClass.DeviceID = 42;


            // add mySecondClass to the SecondClassList
            myReportsHolder.SecondClassReportList.Add(mySecondClass);

            // add the report holder to the root object
            myReportSpec.ReportsList.Add(myReportsHolder);

            // serialize and create file
            serializer.Serialize(writer, myReportSpec); <-- Will this produce the format I am looking for?
            writer.Close();
        }
    }

Here is the XML output I am expecting:

<?xml version="1.0" encoding="utf-8"?>
<ReportSpec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="4.5" Username="My Name" xmlns="ReportAutomation Test Application">
    <FirstClassReportsList>
        <FirstClass ReportName="Base Camp Report" FilterMode="Container" Destination="someone@somewhere.com" Format="PDF" >
            <AlertSource>Base Camp 1</AlertSource>
        </FirstClass>
        <FirstClass ReportName="Satellite Stations Report" FilterMode="Container" Destination="\\path\on\my\network" Format="DOC" >
            <AlertSource>Satellite Station 1</AlertSource>
        </FirstClass>
    </FirstClassReportsList>

    <SecondClassReportsList ReportName="Device Inventory Report" FilterMode="Container" Destination="someone@somewhere.com" Format="PDF" >
        <SecondClass>
            <DeviceID>42</DeviceID>
        </SecondClass>
    </SecondClassReportsList>
</ReportSpec>

If I am creating an instance of the FirstClass object, and setting the properties of it, and if I am creating an instance of the ReportsHolder class to put my objects into, why am I getting the "Object reference" error? I am self-teaching serialization as I go along, so this is all a little overwhelming for me.

Kulstad
  • 79
  • 8

1 Answers1

0

You need to create the Lists before you add Items to them:

you could do this in the constructor (this way you don't tend to forget it inside the program):

public class ReportSpec{
    [System.Xml.Serialization.XmlElementAttribute("Report")]
    public List<ReportsHolder> ReportsList { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public double Version { get; set; }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Username { get; set; }

    public ReportSpec()
    {
        this.ReportsList = new List<ReportsHolder>();
    }    
}

and

public class ReportsHolder{
    public List<FirstClass> FirstClassReportsList { get; set; }
    public List<SecondClass> SecondClassReportList { get; set; }

    public ReportsHolder()
    {
        this.FirstClassReportsList = new List<FirstClass>();
        this.SecondClassReportList = new List<SecondClass>();
    }    
}

from now on you can add items to your lists

To the second part of your question:

serializer.Serialize(writer, myReportSpec); <-- Will this produce the format I am looking for?

your expected format is the structure of the ReportsHolder class not that of the ReportSpec. So you should serialize myReportsHolder

serializer.Serialize(writer, myReportsHolder); 

but then the first tag will be of course <ReportsHolder...

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • As to the first part of my question: thank you! I find it's often the little things that get overlooked that cause the biggest headache, and this is certainly an example of it. As to the second part: serializing `myReportsHolder misses out on the root object myReportSpec, so I need to serialize myReportSpec in order to produce what is required. – Kulstad Jul 06 '16 at 15:44
  • The XML that you get from your code should differ from your expected format. There should be also a node , or am I wrong? – Mong Zhu Jul 06 '16 at 17:57
  • 1
    You are correct. The output structure is now ReportSpec --> Report --> ReportList (and after a small addition, it continues Filters --> FilterName). Now I need to figure out how move the attributes from the ReportList to the Report, make the Filters part of the Report, and eliminate the ReportList altogether, but that's another topic for a different question. – Kulstad Jul 06 '16 at 19:15