简体   繁体   中英

Missing object when deserializing

I have a weird issue and am confused. I want to send a dataset over the wire and serialize it. When I deserialize, I want to retrieve the object and it's properties. However, when I DESERIALIZE (EDITED), it seems to lose the child classes associated with the base class. I created the following class:

 [Serializable]
    public class DataAttributeColumn : DataColumn, ISerializable
    {

        private string attributeName;

        [DataMember(IsRequired = true)]
        public string AttributeName
        {
            get { return attributeName; }
            set { attributeName = value; }
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("AttributeName", this.AttributeName);
        }
    }

Instead of using column name for a DataColumn, I wanted to extend it an add an attribute name. This all works 100% up until I send it over the wire.

I created the following Test class and used Binary and DataContract serializer.

public class Test
    {
        DataSet ds = new DataSet();
        DataTable dt = new DataTable();
        DataAttributeColumn dac = new DataAttributeColumn();

        public void CreateData()
        {
            ds.Tables.Add(dt);
            dac.AttributeName = "MyAttribute";
            dt.Columns.Add(dac);

        }

        public void SerializeBinary()
        {
            DataSet dss = new DataSet();

            BinaryFormatter dcs = new BinaryFormatter();
            ds.RemotingFormat = SerializationFormat.Xml;

            string strTempfilePath = "binary.txt";
            FileStream fs;
            using (fs = new FileStream(strTempfilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                dcs.Serialize(fs, ds);
            }

            fs = new FileStream(strTempfilePath, FileMode.Open);
            dss = dcs.Deserialize(fs) as DataSet;

            DataAttributeColumn dac2 = null;
            dac2 = dss.Tables[0].Columns[0] as DataAttributeColumn;

            if (dac2 != null)
            {
                Console.WriteLine("YOU DID IT!!!!");
            }
            //Second Serialize
            using (fs = new FileStream("binary2.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                dcs.Serialize(fs, dss);
            }
        }
        public void SerializeDataContract()
        {
            DataSet dss = new DataSet();

            Type[] knowntypes = { typeof(DataAttributeColumn), typeof(DataColumn) };
            DataContractSerializer dcs = new DataContractSerializer(typeof(DataSet), knowntypes);
            MemoryStream stream = new MemoryStream();
            ds.RemotingFormat = SerializationFormat.Xml;

            string strTempfilePath = "datacontract.txt";
            FileStream fs;
            using (fs = new FileStream(strTempfilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                dcs.WriteObject(fs, ds);
            }

            fs = new FileStream(strTempfilePath, FileMode.Open);
            dss = dcs.ReadObject(fs) as DataSet;

            DataAttributeColumn dac2 = null;
            dac2 = dss.Tables[0].Columns[0] as DataAttributeColumn;
            if (dac2 != null)
            {
                Console.WriteLine("YOU DID IT!!!!");
            }

            using (fs = new FileStream("datacontract2.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                dcs.WriteObject(fs, dss);
            }
        }
    }

My goal is to create an attribute and when I deserialize, I get to cast the object from DataColumn back into DataAttributeColumn in order to retrieve the "AttributeName".

How can I come to do this?

EDIT: The output after serializatiion

<DataSet><xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"><xs:complexType><xs:choice minOccurs="0" maxOccurs="unbounded"><xs:element name="Table1"><xs:complexType><xs:sequence><xs:element name="Column1" msdata:**AttributeName="MyAttribute"** type="xs:string" minOccurs="0"/></xs:sequence></xs:complexType></xs:element></xs:choice></xs:complexType></xs:element></xs:schema><diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"/></DataSet>

and output after deserialization:

<DataSet><xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"><xs:complexType><xs:choice minOccurs="0" maxOccurs="unbounded"><xs:element name="Table1"><xs:complexType><xs:sequence><xs:element name="Column1" type="xs:string" minOccurs="0"/></xs:sequence></xs:complexType></xs:element></xs:choice></xs:complexType></xs:element></xs:schema><diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"/></DataSet>

The key is in the following line:

Type[] knowntypes = { typeof(DataAttributeColumn), typeof(DataColumn) };

You need to use these knowntypes with every Serialize or Deserialize every time. This way the formatter will know to save a proper actual class, even if the array containing it is declared with subclasses. Check your own code, you are using it correctly in one place, but not in the others!

Lets try a different approach. Use XmlSerializer:

        XmlSerializer serializer = new XmlSerializer(typeof(DataSet));
        FileStream fs = new FileStream(yourFilePath, FileMode.Create);
        XmlWriterSettings Settings = new XmlWriterSettings(); //Please use this!
        Settings.Indent = true;
        Settings.IndentChars = "  ";
        Settings.NewLineHandling = NewLineHandling.None;
        Settings.NewLineChars = "\n";
        XmlWriter writer = XmlWriter.Create(fs, Settings); 
        //XmlWriter writer = new XmlTextWriter(fs, Encoding.ASCII);
        serializer.Serialize(writer, ds);
        writer.Close();
        fs.Close();

To deserialize use:

        XmlReader reader = new XmlTextReader(fs);
        DataSet ds2 = (DataSet)serializer.Deserialize(reader);
        reader.Close();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM