When a user uses my program, it will generate many thousands of objects over the course of a couple of hours. These cannot accumulate in RAM, so I want to write them to a single file as they are generated. Then, in a different program, the objects must all be deserialized.
When I try to serialize different objects of the same class to the same XML file and then try to deserialize later, I get:
System.InvalidOperationException: 'There is an error in XML document (1, 206).'
Inner Exception
XmlException: There are multiple root elements. Line 1, position 206.
Here is an example of a .NET 6.0 console app that recapitulates this problem:
using System.Xml.Serialization;
using System.IO;
using System.Xml;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
// Serialize a person
using (FileStream stream = new FileStream("people.xml", FileMode.Create))
{
Person jacob = new Person { Name = "Jacob", Age = 33, Alive = true };
XmlSerializer serializer = new XmlSerializer(typeof(Person));
serializer.Serialize(stream, jacob);
}
// Serialize another person to the same file using the "clean XML" method
// https://stackoverflow.com/questions/1772004/how-can-i-make-the-xmlserializer-only-serialize-plain-xml
using (StreamWriter stream = new StreamWriter("people.xml", true))
{
Person rebecca = new Person { Name = "Rebecca", Age = 45, Alive = true };
stream.Write(SerializeToString(rebecca));
}
// Deserialize the people
List<Person> people = new List<Person>();
using (FileStream stream = new FileStream("people.xml", FileMode.Open))
{
XmlSerializer deserializer = new XmlSerializer(typeof(Person));
while (stream.Position < stream.Length)
{
people.Add((Person)deserializer.Deserialize(stream));
}
}
// See the people
foreach (Person person in people)
Console.WriteLine($"Hello. I am {person.Name}. I am {person.Age} and it is {person.Alive} that I am alive.");
}
// Serialize To Clean XML
public static string SerializeToString<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool Alive { get; set; }
public Person()
{
Name = "";
}
}
}