Serialize C# dynamic and Anonymous types to XML

Dynamic / Anonymous types in C# was a great improvement to the framework, made in version 3.0. I use it a lot when doing AJAX callbacks from JavaScript to ASP.NET MVC Controllers, not to forget the extensive use of anonymous types already used in ASP.NET MVC.

Then yesterday, one case where I absolutely needed to use anonymous types was in my application’s logging service. I want to be able to save behaviors/actions as well as errors. I have two separate tables, but both behaviors and errors can provide a set of details. To do the actual logging, I call an implementation of this interface:

///

/// Defines methods for logging errors and behavior./// [ServiceContract] publicinterface ILogService { /// /// Logs the behavior with data./// /// The application instance id./// The action./// The log date./// The user agent./// The behavior data./// The source. [OperationContract] void LogBehaviorWithData(int applicationInstanceId, string action, DateTime logDate, string userAgent, string behaviorData, string source); /// /// Logs the behavior./// /// The application instance id./// The action./// The log date./// The user agent./// The source. [OperationContract] void LogBehavior(int applicationInstanceId, string action, DateTime logDate, string userAgent, string source); }

In the LogBehaviorWithData method, I wanted to specify behaviorData as XML, since the column in the database is an XML column. I do this, so that I’m able to query the table and using XPath to filter on behavior data. That requires me to send XML to the method, and I don’t want to fool around manually with an XmlDocument or something similar.

I was looking around the internet for a way to serialize an anonymous type to XML, and came across a few questions on StackOverflow. The first one accepted there’s no way to do that – even though there was a fine answer below, and the second didn’t provide a solution. I took the code provided by Matthew Whited in his excellent answer (that I don’t believe is not the correct answer of the question). It worked out of the box, except for Arrays, so that needed some extensions.

How to use it

It’s simply an *Extension Method of the object type, *called ToXml(). And it is used like this:

object d = new { Username = "martin", Roles = new[] { "Developer", "Administrator" } }; XElement xml = d.ToXml(); string xmlString = xml.ToString();

The output is a beautifully formatted XML string:

<object><Username>martinUsername><Roles><RolesChild>DeveloperRolesChild><RolesChild>AdministratorRolesChild>Roles>object>

 

To make it more database friendly, you can omit the formatting by specifying SaveOptions in the ToString method call:

string xmlString = xml.ToString(SaveOptions.DisableFormatting);

The actual code

The actual code is quite simple, yet there’s some fiddling around with different types and such. I guess the name of child elements could also need some improvement, preferably changing the collection name to a* singular representation* and use that as the element name of its children.

using System; using System.Linq; using System.Reflection; using System.Xml; using System.Xml.Linq; ///

/// Extension methods for the dynamic object./// publicstaticclass DynamicHelper { /// /// Defines the simple types that is directly writeable to XML./// privatestaticreadonly Type[] _writeTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid) }; /// /// Determines whether [is simple type] [the specified type]./// /// The type to check./// /// true if [is simple type] [the specified type]; otherwise, false./// publicstaticbool IsSimpleType(this Type type) { return type.IsPrimitive || _writeTypes.Contains(type); } /// /// Converts an anonymous type to an XElement./// /// The input./// Returns the object as it's XML representation in an XElement.publicstatic XElement ToXml(thisobject input) { return input.ToXml(null); } /// /// Converts an anonymous type to an XElement./// /// The input./// The element name./// Returns the object as it's XML representation in an XElement.publicstatic XElement ToXml(thisobject input, string element) { if (input == null) { returnnull; } if (String.IsNullOrEmpty(element)) { element = "object"; } element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = from prop in props let name = XmlConvert.EncodeName(prop.Name) let val = prop.PropertyType.IsArray ? "array" : prop.GetValue(input, null) let value = prop.PropertyType.IsArray ? GetArrayElement(prop, (Array)prop.GetValue(input, null)) : (prop.PropertyType.IsSimpleType() ? new XElement(name, val) : val.ToXml(name)) wherevalue != null select value; ret.Add(elements); } return ret; } /// /// Gets the array element./// /// The property info./// The input object./// Returns an XElement with the array collection as child elements.privatestatic XElement GetArrayElement(PropertyInfo info, Array input) { var name = XmlConvert.EncodeName(info.Name); XElement rootElement = new XElement(name); var arrayCount = input.GetLength(0); for (int i = 0; i < arrayCount; i++) { var val = input.GetValue(i); XElement childElement = val.GetType().IsSimpleType() ? new XElement(name + "Child", val) : val.ToXml(); rootElement.Add(childElement); } return rootElement; } }

That way it is possible to serialize an anonymous type in C# to XML.

Download

Download the class from my SkyDrive.

Martin H. Normark

Product and UX Hacker. Web and iOS developer.

Subscribe to Martin Normark's Blog

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!