When deserializing XML from a memory mapped file, how can I fix “SerializationException: The data at the root level is invalid. Line 1, position 1”

When deserializing XML from a memory mapped file, I am getting below error while calling DataContractSerializer.ReadObject():

System.Runtime.Serialization.SerializationException: ‘There was an error deserializing the object of type SampleClass. The data at the root level is invalid. Line 1, position 1.’

I previously wrote the XML to the file using DataContractSerializer and so it should be valid. How can I fix this?

Adding my sample code below:

using System.IO.MemoryMappedFiles;
using System.Runtime.Serialization;
using System.Runtime.Versioning;

namespace TestMigration
{
    public class Program
    {
        [SupportedOSPlatform("windows")]
        public static void Main(string[] args)
        {
            using (var mmf = MemoryMappedFile.CreateNew("TempName", 10240, MemoryMappedFileAccess.ReadWrite))
            {
                WriteToMemoryMappedFile(mmf);

                var infoObj = ReadFromMemoryMappedFile(mmf);

                Console.WriteLine(infoObj?.Name);
            }

        }
        private static void WriteToMemoryMappedFile(MemoryMappedFile mmf)
        {
            var serializer = new DataContractSerializer(typeof(SampleClass));

            var infoObj = new SampleClass { Name = "TestApp" };

            using (var stream = mmf.CreateViewStream(0, 0, MemoryMappedFileAccess.Write))
            {
                serializer.WriteObject(stream, infoObj);
                stream.Flush();
            }
        }

        private static SampleClass? ReadFromMemoryMappedFile(MemoryMappedFile mmf)
        {
            var serializer = new DataContractSerializer(typeof(SampleClass));

            using (var stream = mmf.CreateViewStream(0, 0, MemoryMappedFileAccess.Read))
            {
                stream.Position = 0;
                return (SampleClass?)serializer.ReadObject(stream);
            }
        }
    }
}

[DataContract]
public class SampleClass
{
    [DataMember]
    public string? Name { get; set; }
}

Please do not mark this as duplicate, I tried adding workarounds such as using XmlReader, XmlDictionaryReader etc as suggested in other questions but didn’t work out.

Your problem is that, one created, memory mapped files have a fixed size [1]. Therefore, after you write your XML to your view stream, the file will contain your XML plus enough uninitialized bytes to pad the length out to the fixed length of 10240. You can confirm this by printing the value of stream.Length in WriteToMemoryMappedFile():

using (var stream = mmf.CreateViewStream(0, 0, MemoryMappedFileAccess.Write))
{
    Debug.WriteLine(stream.Length); // Prints 10240

Because of the trailing padding, your memory mapped file is a malformed XML document. And the XmlReader created internally by DataContractSerializer.ReadObject() is designed to verify that by reading past the end of the root object to ensure that the entire file is in fact well-formed. Since it isn’t, you get the exception you see.

So what are your options for a workaround?

Firstly, you could treat your memory mapped file as a sequence of XML fragments, and read only the first fragment. First introduce the following extension method:

public static partial class DataContractSerializerExtensions
{
    public static IEnumerable<T?> ReadObjectFragments<T>(Stream stream, DataContractSerializer? serializer = null, bool closeInput = true)
    {
        var settings = new XmlReaderSettings
        {
            ConformanceLevel = ConformanceLevel.Fragment,
            CloseInput = closeInput,
        };
        serializer ??= new DataContractSerializer(typeof(T));
        using (var outerReader = XmlReader.Create(stream, settings))
        {
            while (outerReader.Read())
            {   // Skip whitespace
                if (outerReader.NodeType == XmlNodeType.Element)
                    using (var innerReader = outerReader.ReadSubtree())
                    {
                        yield return (T?)serializer.ReadObject(innerReader);
                    }
            }
        }
    }
}

And then modify ReadFromMemoryMappedFile() as follows:

private static SampleClass? ReadFromMemoryMappedFile(MemoryMappedFile mmf)
{
    using (var stream = mmf.CreateViewStream(0, 0, MemoryMappedFileAccess.Read))
    {
        return DataContractSerializerExtensions.ReadObjectFragments<SampleClass>(stream).FirstOrDefault();
    }
}

Your SampleClass will now be deserialized successfully, as the call to FirstOrDefault() combined with the use of ConformanceLevel.Fragment prevents the underlying XmlReader from attempting to read beyond the initial fragment.

Demo fiddle #1 here.

Secondly, since your memory mapped file isn’t well-formed XML anyway, you could consider adopting a message framing approach by writing the actual data size before the XML content.

To do that, first create the following generic methods:

public static partial class MemoryMappedFileExtensions
{
    static readonly int LongSize = Marshal.SizeOf<long>();

    public static void WriteAndFrame<T>(this MemoryMappedFile mmf, T value, long offset = 0, DataContractSerializer? serializer = null)
    {
        long actualSize;
        serializer ??= new DataContractSerializer(typeof(T));
        
        // Write the data contract data at offset 8.
        using (var stream = mmf.CreateViewStream(checked(offset + LongSize), 0, MemoryMappedFileAccess.Write))
        {
            var startPosition = stream.Position;
            serializer.WriteObject(stream, value);
            stream.Flush();
            actualSize = stream.Position - startPosition;
        }
        
        // Write the message frame size at offset 0.
        using (var accessor = mmf.CreateViewAccessor(offset, LongSize))
        {
            accessor.Write(0, actualSize);
        }
    }
    
    public static T? ReadFromFrame<T>(this MemoryMappedFile mmf, long offset = 0, DataContractSerializer? serializer = null)
    {
        long actualSize;
        serializer ??= new DataContractSerializer(typeof(T));

        // Read the message frame size from offset zero.
        using (var accessor = mmf.CreateViewAccessor(offset, LongSize))
        {
            accessor.Read(0, out actualSize);
        }

        // Read the XML starting at offset 8 with the specified message frame size.
        using (var stream = mmf.CreateViewStream(offset + LongSize, actualSize, MemoryMappedFileAccess.Read))
        {
            return (T?)serializer.ReadObject(stream);
        }
    }
}

And now your read and write methods can be rewritten as follows:

private static void WriteToMemoryMappedFile(MemoryMappedFile mmf)
{
    var infoObj = new SampleClass { Name = "TestApp" };
    
    mmf.WriteAndFrame(infoObj);
}

private static SampleClass? ReadFromMemoryMappedFile(MemoryMappedFile mmf) =>
    mmf.ReadFromFrame<SampleClass>();

Demo fiddle #2 here.

Finally, you might consider whether your approach of using memory mapped files to hold a single XML document is ideal, given that the file size must be fixed in advance.


[1]See How to dynamically expand a Memory Mapped File for a discussion.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật