C# Serializing datacontracts from file

China☆狼群 提交于 2019-12-23 13:18:07

问题


I have a list of Xml messages specifically DataContract messages that i record to a file. And i am trying to deserialize them from file one by one. I do not want to read the whole file into memory at once because i expect it to be very big.

I have an implementation of this serialization and that works. I did this by serializing using a FileStream and reading the bytes and using regular expression to determine the end of element. Then taking the element and using DataContractSerializer to get the actual object.

But i was told I should be using higher level code to do this task and it seems like that should be possible. I have the following code that i think should work but it doesn't.

FileStream readStream = File.OpenRead(filename);
DataContractSerializer ds = new DataContractSerializer(typeof(MessageType));
MessageType msg;
while ((msg = (MessageType)ds.ReadObject(readStream)) != null)
{
    Console.WriteLine("Test " + msg.Property1);
}

The above code is fed with an input file containing something along the following lines:

<MessageType>....</MessageType>
<MessageType>....</MessageType>
<MessageType>....</MessageType>

It appears that i can read and deserialize the first element correctly but after that it fails saying:

System.Runtime.Serialization.SerializationException was unhandled
  Message=There was an error deserializing the object of type MessageType. The data at the root level is invalid. Line 1, position 1.
  Source=System.Runtime.Serialization

I have read somewhere that it is due to the way DataContractSerializer works with padded '\0''s to the end - but i couldn't figure out how to fix this problem when reading from a stream without figuring out the end of MessageType tag in some other way. Is there another Serialization class that i should be using? or perhaps a way around this problem?

Thanks!


回答1:


When you're deserializing the data from the file, WCF uses by default a reader which can only consume proper XML documents. The document which you're reading isn't - it contains multiple root elements, so it's effectively a fragment. You can change the reader the serializer is using by using another overload of ReadObject, as shown in the example below, to one which accepts fragments (by using the XmlReaderSettings object). Or you can have some sort of wrapping element around the <MessageType> elements, and you'd read until the reader were positioned at the end element for the wrapper.

public class StackOverflow_7760551
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }

        public override string ToString()
        {
            return string.Format("Person[Name={0},Age={1}]", this.Name, this.Age);
        }
    }

    public static void Test()
    {
        const string fileName = "test.xml";
        using (FileStream fs = File.Create(fileName))
        {
            Person[] people = new Person[]
            { 
                new Person { Name = "John", Age = 33 },
                new Person { Name = "Jane", Age = 28 },
                new Person { Name = "Jack", Age = 23 }
            };

            foreach (Person p in people)
            {
                XmlWriterSettings ws = new XmlWriterSettings
                {
                    Indent = true,
                    IndentChars = "  ",
                    OmitXmlDeclaration = true,
                    Encoding = new UTF8Encoding(false),
                    CloseOutput = false,
                };
                using (XmlWriter w = XmlWriter.Create(fs, ws))
                {
                    DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
                    dcs.WriteObject(w, p);
                }
            }
        }

        Console.WriteLine(File.ReadAllText(fileName));

        using (FileStream fs = File.OpenRead(fileName))
        {
            XmlReaderSettings rs = new XmlReaderSettings
            {
                ConformanceLevel = ConformanceLevel.Fragment,
            };
            XmlReader r = XmlReader.Create(fs, rs);
            while (!r.EOF)
            {
                Person p = new DataContractSerializer(typeof(Person)).ReadObject(r) as Person;
                Console.WriteLine(p);
            }
        }

        File.Delete(fileName);
    }
}



回答2:


Maybe your file contains BOM It's common for UTF-8 encoding




回答3:


XmlSerializer xml = new XmlSerializer(typeof(MessageType));
XmlDocument xdoc = new XmlDocument();
xdoc.Load(stream);
foreach(XmlElement elm in xdoc.GetElementsByTagName("MessageType"))
{
    MessageType mt = (MessageType)xml.Deserialize(new StringReader(elm.OuterXml)); 
}


来源:https://stackoverflow.com/questions/7760551/c-sharp-serializing-datacontracts-from-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!