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.