I'm currently using
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
XmlDictionaryWriter xdw = XmlDictionaryWriter.CreateTextWriter(filestream, Encoding.UTF8);
dcs.WriteObject(xdw, obj);
In order to write out XML, I've heard good things about the WCF DataContractSerializer in terms of it's performance, and ability to provide forwards compatibility.
However, it's impossible to pass in settings to XmlDictionaryWriter.
I don't 100% understand the differences between XmlDictionaryWriter and a normal XmlWriter with custom settings, and it's impossible to tweak the settings of XmlDictionaryWriter as far as I'm aware.
So what are the differences between XmlDictionaryWriter and XmlWriter (yes one is a super class, but I'm talking concretely, vs var XmlWriter = XmlWriter.Create(filestream, settings);
)
And what settings can I use in order to imitate XmlDictionaryWriter as close as possible, except for having indentation set to true?
I've currently got
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = Encoding.UTF8,
IndentChars = " "
};
As my settings for the XmlWriter, whereas XmlDictionaryWriter appears to have null Settings. (XmlDictionaryWriter.Settings
is both null and readonly, so that's a bust.)
My end goal is to have formatted XML, so maybe if the changes aren't too severe I can just use a hand created XmlWriter anyway.
Comparing the two using NUnit results in
XmlDictionaryWriter
:
"<Party xmlns=\"http://schemas.datacontract.org/2004/07/HeliSTATS.Test\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Guests><Larry><Age>12</Age><Friend><Name>John</Name></Friend></Larry><Larry><Age>15</Age><Friend><Name>Mason</Name></Friend></Larry></Guests></Party>"
XmlWriter
:
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Party xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/HeliSTATS.Test\">\r\n <Guests>\r\n <Larry>\r\n <Age>12</Age>\r\n <Friend>\r\n <Name>John</Name>\r\n </Friend>\r\n </Larry>\r\n <Larry>\r\n <Age>15</Age>\r\n <Friend>\r\n <Name>Mason</Name>\r\n </Friend>\r\n </Larry>\r\n </Guests>\r\n</Party>"
You're actually asking a few separate questions:
What is the differences between XmlDictionaryWriter
and XmlWriter
?
This question is addressed in XMLWriter vs XMLDictionaryWriter with answers by Bronumski and Mike McCaughan. The conclusion is that XmlDictionaryWriter
is used
In addition, some functionality of DataContractSerializer
only works with XmlDictionaryWriter
. E.g. if you need to serialize an object using a custom DataContractResolver
you will need to use DataContractSerializer.WriteObject(XmlDictionaryWriter, Object, DataContractResolver)
because there is no overload of WriteObject()
that takes both an XmlWriter
and a DataContractResolver
.
How can I use XmlDictionaryWriter
and also control XmlWriterSettings
?
If you are sure you need to use XmlDictionaryWriter
(for performance reasons, or because you need to use a DataContractResolver
) then you can construct one that wraps a pre-existing XmlWriter
by using XmlDictionaryWriter.CreateDictionaryWriter(XmlWriter)
.
What settings can I use in order to imitate XmlDictionaryWriter
with XmlWriter
as closely as possible while still indenting?
You don't. You use the one you need, and if you need the functionality of both, create a wrapped XmlWriter
as shown above.
Putting all of the above together, the following extension methods can be used to serialize with both XmlDictionaryWriter
and optional XmlWriterSettings
:
public static partial class DataContractSerializerExtensions
{
public static string ToContractXml<T>(this T obj, DataContractSerializer serializer = null, XmlWriterSettings settings = null, DataContractResolver resolver = null)
{
serializer = serializer ?? new DataContractSerializer(obj == null ? typeof(T) : obj.GetType());
using (var textWriter = new StringWriterWithEncoding((settings == null ? null : settings.Encoding) ?? Encoding.UTF8))
{
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj, resolver);
}
return textWriter.ToString();
}
}
public static void WriteObject(this DataContractSerializer serializer, Stream stream, object obj, XmlWriterSettings settings, DataContractResolver resolver = null)
{
if (serializer == null || stream == null)
throw new ArgumentNullException();
// If settings are specified create a wrapped dictionary writer, else create a text writer directly.
if (settings == null)
{
// Let caller close the stream
using (var xmlWriter = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
{
serializer.WriteObject(xmlWriter, obj, resolver);
}
}
else
{
using (var xmlWriter = XmlWriter.Create(stream, settings))
{
serializer.WriteObject(xmlWriter, obj, resolver);
}
}
}
static void WriteObject(this DataContractSerializer serializer, XmlWriter xmlWriter, object obj, DataContractResolver resolver)
{
if (serializer == null || xmlWriter == null)
throw new ArgumentNullException();
using (var xmlDictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter))
{
serializer.WriteObject(xmlDictionaryWriter, obj, resolver);
}
}
}
Then, profile WriteObject()
with and without XmlWriterSettings
to determine the performance impact of using a wrapped XmlWriter
.