.NET Version 2.0 XML Readers and Writers

The recommended way to create XML readers and writers has changed from .NET 1.1 to .NET 2.0.  In .NET 1.1, you use the new operator to create an instance of XmlTextReader or XmlTextWriter.  In .NET 2.0, you use the Create function of XmlReader or XmlWriter to create instances.  This is more than simply a different way of coding things; the reader/writer you get in 2.0 behaves differently than its 1.1 version.

For example, the following 1.1 code, while it compiles, does not work correctly:

using System;
using System.IO;
using System.Text;
using System.Xml;

protected MemoryStream createReplyMessage(string messageType, string replyText, Exception exception) {
	MemoryStream replyStream = new MemoryStream();
	using (XmlTextWriter reply = new XmlTextWriter(replyStream, Encoding.UTF8)) {
		reply.WriteStartDocument();
		reply.WriteStartElement("Reply");
		reply.WriteAttributeString("Type", messageType);
		reply.WriteElementString("Text", replyText);
		if (exception != null) reply.WriteElementString("Exception", exception.Message);
		reply.WriteEndElement();
		reply.WriteEndDocument();
		reply.Flush();
	}
	replyStream.Position = 0;
	return replyStream;
} 

The problem is the closing of the XmlTextWriter.  It thinks it owns the backing store (the MemoryStream).  When the XmlTextWriter is disposed of the backing store is also disposed of.  Removing the using construct won't help; that will make matters worse.  Without the using construct, you would return the undisposed MemoryStream, but at some point the garbage collector would decide to collect the unreferenced XmlTextWriter and then the MemoryStream would be disposed.  In other words, the returned MemoryStream would disappear at some random time!

When you use the Create function in .NET 2.0, the reader/writer no longer considers itself the owner of the backing store.  For example, the following code works correctly (note the change in the using construct):

using System;
using System.IO;
using System.Text;
using System.Xml;

protected MemoryStream createReplyMessage(string messageType, string replyText, Exception exception) {
	MemoryStream replyStream = new MemoryStream();
	using (XmlWriter reply = XmlWriter.Create(replyStream)) {
		reply.WriteStartDocument();
		reply.WriteStartElement("Reply");
		reply.WriteAttributeString("Type", messageType);
		reply.WriteElementString("Text", replyText);
		if (exception != null) reply.WriteElementString("Exception", exception.Message);
		reply.WriteEndElement();
		reply.WriteEndDocument();
		reply.Flush();
	}
	replyStream.Position = 0;
	return replyStream;
}

And what if you want the backing store to be disposed of when the reader/writer is disposed of?  The Create function takes a second argument, of type XmlReaderSettings or XmlWriterSettings as appropriate, where you can set the CloseInput (XmlReaderSettings) or CloseOutput (XmlWriterSettings) flag to true.  The two settings classes also contain other members you can use to exactly control reader/writer creation.

Print | posted @ Saturday, October 21, 2006 6:06 AM

Comments on this entry:

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: