0

When trying to read from a MemoryStream (which was written to by an XmlWriter), it throws an ObjectDisposedException ("Cannot access a closed Stream.").

I stumbled upon the fact that closing the XmlWriter in the middle of the 'using' statement allows to code to return without throwing. Something is fishy here.

    public static string SerializeToString(T obj)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));

        using (var stream = new MemoryStream())
        using (var writer = XmlWriter.Create(stream))
        {
            serializer.Serialize(writer, obj);

            writer.Flush();
            // Swapping the flush for close fixes the ObjectDisposedException 
            //writer.Close();
            stream.Position = 0;


            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }

This happens for both Silverlight and .NET 4.5.

After reading around I could read a string from the memory stream directly as per Jon's answer here return Encoding.UTF8.GetString(stream.GetBuffer(), 0, stream.Length);

But first I'd like to understand what is happening to cause the exception in the example code.

Community
  • 1
  • 1
aitee
  • 91
  • 1
  • 1
  • 9

2 Answers2

1

Closing the writer will also Close() the underlying stream object.

You don't need to close the writer explicitly, as the using statement will do that for you automatically at the end of the block.

using (var stream = new MemoryStream())
using (var writer = XmlWriter.Create(stream))
{       
    ...
    //writer.Close(); <=== don't do this
    ...
} // <=== stream and writer get closed here
thumbmunkeys
  • 20,606
  • 8
  • 62
  • 110
  • I understand that. But without the close the reader.ReadToEnd() throws. That is what this question is about. – aitee Apr 12 '16 at 17:27
-1

The issue that the example code is exhibiting is double disposing (the StreamReader and the XmlWriter both dispose their BaseStream[MemoryStream]).

Putting the StreamReader into the top block of usings fixes the issue.

But in the end I didn't need to StreamReader to get the text out and went with the following:

        public static string SerializeToString(T obj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            using (var memoryStream = new MemoryStream())
            using (var writer = XmlWriter.Create(memoryStream))
            {
                serializer.Serialize(writer, obj);
                return Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
            }
        }
aitee
  • 91
  • 1
  • 1
  • 9
  • 1
    Very bad recommendation - don't follow - always dispose `IDisposable` objects. You can use `MemoryStream.GetBuffer` and `MemoryStream.ToArray` on disposed `MemoryStream` as they exists exactly for that reason. – Alexei Levenkov Apr 12 '16 at 18:19
  • Can you please post your solution? When utilizing two nested usings, an exception occurs for disposing the base stream twice. The only reason I answered my question was to try to shed light on what is causing the problem when using the nested 'using' statements in the original code snippet. – aitee Apr 14 '16 at 19:19
  • Code has been updated. Even when disposing the XmlWriter. The MemoryStream cannot be put into the using as it throws when dispose is called on an already closed stream. If you have a better or more correct solution I'd really appreciate it if you would go ahead and post it. Thanks! – aitee Apr 14 '16 at 19:58
  • It also appears (at least in Silverlight) that you cannot access MemoryStream's GetBuffer after the MemoryStream has been closed. – aitee Apr 14 '16 at 20:11
  • I don't believe MemeoryStream throws exception when being disposed twice... Note that CA2202 is known to be problematic in this exact case - http://stackoverflow.com/questions/3831676/ca2202-how-to-solve-this-case – Alexei Levenkov Apr 14 '16 at 21:03
  • Hmm, interesting. Well, something is getting disposed twice and throwing the ObjectDisposedException in the original code snippet. Not sure what else could be throwing the exception besides the MemoryStream. Thanks for the link – aitee Apr 15 '16 at 17:21
  • According to the link you posted, it shouldn't be the double dispose, but could be another instance method being called once the object is disposed. But the ReadToEnd() call is inside the dispose. hmm. – aitee Apr 15 '16 at 17:27