’m a big fan of XAML. It provides a nice, declarative, toolable way of defining UI, encourages separation of UI logic and application logic, and is flexible enough to allow an impressive amount of expressiveness. In addition to being a way to describe a user interface, XAML can be used as a serialization format for arbitrary CLR objects. A little over a month ago, as I was building out a prototype of an idea I had for a blog post for another time, I found myself looking for a way to quickly and easily serialize some data out into Isolated Storage. I looked at a few options, such as the XML and JSON serializers in the Silverlight SDK. Both of these work well for serialization of data, but as I was looking at them, I noticed something that failed to meet my requirements for the task at hand: these libraries are both quite large and would need to be packaged into my XAPs. System.Xml.Serialization.dll is 314 kb, and System.Runtime.Serialization.Json.dll is 138 kb (uncompressed). Under many circumstances in large applications, taking such dependencies might be fine, but I was looking for something small that would be acceptable to package into a quick-to-load bootstrapping application. As a result, I thought I’d spend some time looking for another option. It occurred to me that in WPF, I might’ve used the XamlWriter for precisely this purpose: to serialize my objects out into text. As I thought about my options for serialization, taking assembly size into account, I found myself wondering if XAML was a good choice. After all, Silverlight has a reader (XamlReader) built into the runtime, so I wouldn’t have to build one myself. Perhaps that would save me the size I was looking for. Furthermore, in Silverlight 4, the XAML parser got a major overhaul that helped ensure more consistent support of the XAML language, so I felt confident that I could produce a flexible XAML serializer. With that in mind, I started writing. At first, I was just hoping to build out some basic serialization into XAML – enough to suit my needs for what I was working on. But unfortunately, once I start trying to solve a problem, I can’t leave it half-complete! Just like that, I was hooked on the challenge of seeing how complete of a XAML serializer I could build (which helps explain my blogging absence for the last month ). Honestly, I expected to find a large number of issues – limitations of Silverlight that would keep me from collecting enough information to serialize to XAML properly. The reality, however, was that I could actually get really close to full fidelity. In the process, I learned a lot about XAML, Silverlight, and myself (a journey of self-discovery, so to speak ). In this post, I’ll share my results (happily included for your consumption and experimentation in my latest build of SLaB) as well as some of what I learned. As usual, I make no promises around support or correctness in all cases. This is sample code for your edification. That said, if you do find an issue, please let me know, and I’ll see if I can figure out what’s going on! POCO, oh, POCO, wherefore art thou?I started out just trying to serialize POCOs (Plain ol’ CLR Objects). On the surface, this is pretty straightforward – walk the object graph being serialized, writing objects and property values out using the XmlWriter. Simple, right? Well, there’s actually a lot going on here: Walk the object graph using reflection
Decide whether properties are serializable (i.e. is the property read-only? If so, is it a collection type?)
Retrieve TypeConverters from both properties and property types (based on the TypeConverterAttribute)
Determine whether to set properties as attributes (<Foo Bar=”Baz” />) or elements (<Foo><Foo.Bar><Baz /></Foo.Bar></Foo>)
Retrieve and honor ContentPropertyAttributes (So that if “Bar” is the ContentProperty of Foo, the example above is serialized as <Foo><Baz /></Foo>)
Determine whether properties should/should not be serialized based on the “ShouldSerializeXXXXX” method and the DefaultValueAttribute
Discover attached properties and repeat all of the above
Manage xml namespace definitions (e.g. xmlns:foo=”clr-namespace:MyAssembly.Foo;assembly=MyAssembly”) and scope
Discover/respect XmlnsDefintion and XmlnsPrefix attributes
Understand serialization of built-in types (e.g. Uri, string, double, int, bool, enums etc.)
Serialize null values (using “{x:Null}”)
Serialize collections
Serialize dictionaries (and make use of “x:Key”)
Properly escape strings (e.g. “{Hello, world!}” needs to get serialized as “{}{Hello World!}”)
Properly handle string whitespace (turning on xml:space=”preserve” at the appropriate times)
Avoid cycles in the object graph (I simply ignore the property if it would cause a cycle – sorry, I’m not a miracle worker!)
Be performant!
Nothing to it, right? Phew, I’m tired just writing all those down! Who knew there was so much to that XAML stuff? (answer: Rob Relyea) Read more: davidpoll.com
Decide whether properties are serializable (i.e. is the property read-only? If so, is it a collection type?)
Retrieve TypeConverters from both properties and property types (based on the TypeConverterAttribute)
Determine whether to set properties as attributes (<Foo Bar=”Baz” />) or elements (<Foo><Foo.Bar><Baz /></Foo.Bar></Foo>)
Retrieve and honor ContentPropertyAttributes (So that if “Bar” is the ContentProperty of Foo, the example above is serialized as <Foo><Baz /></Foo>)
Determine whether properties should/should not be serialized based on the “ShouldSerializeXXXXX” method and the DefaultValueAttribute
Discover attached properties and repeat all of the above
Manage xml namespace definitions (e.g. xmlns:foo=”clr-namespace:MyAssembly.Foo;assembly=MyAssembly”) and scope
Discover/respect XmlnsDefintion and XmlnsPrefix attributes
Understand serialization of built-in types (e.g. Uri, string, double, int, bool, enums etc.)
Serialize null values (using “{x:Null}”)
Serialize collections
Serialize dictionaries (and make use of “x:Key”)
Properly escape strings (e.g. “{Hello, world!}” needs to get serialized as “{}{Hello World!}”)
Properly handle string whitespace (turning on xml:space=”preserve” at the appropriate times)
Avoid cycles in the object graph (I simply ignore the property if it would cause a cycle – sorry, I’m not a miracle worker!)
Be performant!
Nothing to it, right? Phew, I’m tired just writing all those down! Who knew there was so much to that XAML stuff? (answer: Rob Relyea) Read more: davidpoll.com
0 comments:
Post a Comment