I am writing a Web API web service that is returning dynamically constructed property bag. Is there any working serializer or a way how to serialize dynamic to XML? I tried to look for any good suggestions but haven't found anything usable.
1 Answer
We solved it by creating a custom XML formatter.
This isn't an ideal solution but it works.
In the Global.asax
GlobalConfiguration.Configuration.Formatters.Add(new CustomXmlFormatter());
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Create a new class called CustomXmlFormatter
using System;
using System.IO;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace EMP.WebServices.api.Formatters
{
public class CustomXmlFormatter : MediaTypeFormatter
{
public CustomXmlFormatter()
{
SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/xml"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
}
public override bool CanReadType(Type type)
{
if (type == (Type)null)
throw new ArgumentNullException("type");
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task WriteToStreamAsync(Type type, object value,
Stream writeStream, System.Net.Http.HttpContent content,
System.Net.TransportContext transportContext)
{
return Task.Factory.StartNew(() =>
{
var json = JsonConvert.SerializeObject(value);
var xml = JsonConvert
.DeserializeXmlNode("{\"Root\":" + json + "}", "");
xml.Save(writeStream);
});
}
}
}
4 Comments
Troy Alford
That's a fantastic answer. This guarantees that if you're also using the Newtonsoft Json converter, you'll always wind up with the same data being output by both formats - without having to mark up all of your models.
Brian
I would suggest adding a JsonMediaTypeFormatter parameter to CustomXmlFormatter. Then when you call SerializeObject, pass in the JsonMediaTypeFormatter.SerializerSettings. This will make sure you use the same settings to create both JSON and XML.
Rafael Dowling Goodman
For me, this is a really elegant solution to the very issue that @Brian mentions above: I wanted my JSON settings customizations to carry over to the XML media type; thanks for sharing this approach, @Jakub! FWIW, I edited the answer with the implementation I ultimately ended up with that accounts for "array" types and accounts for the ability to deserialize XML.
Chris Gomez
I like the XML this produces better than the built in formatter. However, I found the operation to be extremely fast and the System.Xml.XmlDocument to be just a little more than trivial to use in async code. I didn't use Task.Factory.StartNew to queue this work, but instead derived from BufferedMediaTypeFormatter and found no performance difference under load and didn't create a Task for the sake of complying with the method signature.