I am using WCF to return a plain old XML (POX) document to the caller. I am using the XML Serializer formatter to turn the objects into XML.
In the returned docum
I found a good solution to this issue which lets you inject your own XmlSerializer into WCF that is used when serializing and deserializing requests. This XmlSerializer can be set up to omit XML namespaces entirely (including xmlns:i="w3.org/2001/XMLSchema-instance"
) or any other way you desire.
My solution utilizes WcfRestContrib. You could almost use the included POX formatter but in our case we wanted to support attributes so we wrote our own simple formatter.
Instructions:
1) Reference WcfRestContrib from your project.
2) Create an IWebFormatter
implementation:
public class NamespacelessXmlFormatter : IWebFormatter {
public object Deserialize(WebFormatterDeserializationContext context, Type type) {
if (context.ContentFormat != WebFormatterDeserializationContext.DeserializationFormat.Xml) {
throw new InvalidDataException("Data must be in xml format.");
}
return NamespacelessXmlSerializer.Deserialize(context.XmlReader, type);
}
public WebFormatterSerializationContext Serialize(object data, Type type) {
using (var stream = NamespacelessXmlSerializer.Serialize(data, type)) {
using (var binaryReader = new BinaryReader(stream)) {
byte[] bytes = binaryReader.ReadBytes((int)stream.Length);
return WebFormatterSerializationContext.CreateBinary(bytes);
}
}
}
}
Which utilizes an XmlSerializer that fits your needs (here's ours which simply omits all namespaces):
public static class NamespacelessXmlSerializer {
private static readonly XmlSerializerNamespaces _customNamespace = new XmlSerializerNamespaces();
private static readonly XmlWriterSettings _xmlSettings = new XmlWriterSettings {
OmitXmlDeclaration = true
};
static NamespacelessXmlSerializer() {
// to make sure .NET serializer doesn't add namespaces
_customNamespace.Add(String.Empty, String.Empty);
}
///
/// Deserializes object from its XML representation.
///
///
///
///
public static T Deserialize(Stream stream) {
return (T)Deserialize(stream, typeof(T));
}
///
/// Deserializes object from its XML representation.
///
public static object Deserialize(Stream stream, Type type) {
var ds = new XmlSerializer(type);
var d = ds.Deserialize(stream);
return d;
}
public static object Deserialize(XmlDictionaryReader xmlReader, Type type) {
var ds = new XmlSerializer(type);
var d = ds.Deserialize(xmlReader);
return d;
}
///
/// Serializes object to XML representation.
///
///
/// Is thrown when there was an error generating XML document. This can happen
/// for example if the object has string with invalid XML characters:
/// http://www.w3.org/TR/2004/REC-xml-20040204/#charsets.
/// See this article for other potential issues:
/// http://msdn.microsoft.com/en-us/library/aa302290.aspx
///
public static Stream Serialize(T objectToSerialize) {
return Serialize(objectToSerialize, typeof(T));
}
///
/// Serializes object to XML representation.
///
///
/// Is thrown when there was an error generating XML document. This can happen
/// for example if the object has string with invalid XML characters:
/// http://www.w3.org/TR/2004/REC-xml-20040204/#charsets.
/// See this article for other potential issues:
/// http://msdn.microsoft.com/en-us/library/aa302290.aspx
///
public static Stream Serialize(object objectToSerialize, Type type) {
var stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream, _xmlSettings);
var x = new XmlSerializer(type);
x.Serialize(writer, objectToSerialize, _customNamespace);
stream.Position = 0;
return stream;
}
}
3) Apply the WebDispatchFormatter...
attributes to your service using your custom implementation as the type (based on this documentation):
[WebDispatchFormatterConfiguration("application/xml")]
[WebDispatchFormatterMimeType(typeof(NamespacelessXmlFormatter), "application/xml")]
4) Apply the WebDispatchFormatter
attribute to all of your service methods (based on this documentation).
5) That's it. Test your service and confirm it now behaves as expected.