Menu

More on XML Serialization

November 10, 2014 - .NET, C#, Programming

It seems like each post I do has something to do with XML Serialization lately. And for good reason. The Binary Serialization currently used by BASeBlock (and a few other programs I have) is starting to bother me. It’s black box and there is no way to intelligently account for errors. I tried experimenting with some XML implementations of IFormatter- ideally, I would be able to simply use a different IFormatter implementation and happily save everything. Perhaps I can implement that later; in this case, however, the example I found had a few issues.

  1. It’s 8 years old. That isn’t usually an issue if it works, but in this case it drags along quite a bit of .NET Legacy.
  2. It uses the older System.Xml classes. These work well but they are rather unpleasant to work with because they don’t lend themselves to fluent code. Ideally, I’d like to be using System.Xml.Linq
  3. It doesn’t work for generic types. After struggling with the XML being pretty much stripped off at various points in the code- first trying to serialize a Dictionary’s IComparer, and then arbitrarily at various generic types, it seemed clear the code would require heavy modification to work with BASeBlock because BASeBlock makes heavy use of generic types. So I essentially scrapped it- too much effort to fix up 8 year old code.

So what do I do now? In this case I decided to proceed with my less tasteful method which will require sweeping changes and new interfaces, and basically create a corresponding API set for IFormatter specifically for XML. In my mind it is fairly straightforward. With standard Serialization we write out values to a SerializationInfo object, which is eventually dealt with by the Formatter implementation. This has the issue whereby we lose a lot of extra information, such as what can be an attribute, what needs to be a nested value, etc. So I created a corrolary interface definition:

One mild issue with C# that we encounter here is that we would like to enforce, at compile time, that implementors have a given constructor. We cannot do this as a compile-time contract unfortunately, and if we could define a static interface we could at least require a factory method that does the same. We have to work with it as a run-time contract unfortunately, not unlike the ISerializable interface. This works reasonably well. The GetXMLData() Method creates an XElement representing the object, and a corresponding constructor reconstitutes an instance from that XElement instance.

There is one consideration, of course- and that is classes that we cannot change. In order to make that easier, I’ve created a “IXMLSerializationProvider” interface. This interface is used to define handling code not unlike IXMLSerializable but for code outside of our purview:

Then I construct a helper class- if there is a class type that I cannot change that I need to serialize- such as System.Drawing.Point, System.Drawing.Image, etc. I can implement IXMLSerializationProvider and IXMLSerializationProvider explicitly within that class and provide that capability. The intent is that the Class Library will have a static dictionary or other lookup mechanism such that an arbitrary type can be matched up with the best-match IXMLSerializationProvider implementation available if possible. Then another helper method could easily use IXMLSerializable if the class supports it and save it that way, or use the appropriate IXMLSerializationProvider implementation if present, to create an XElement for a given parameter.

It is looking quite promising. The one thing I do not look forward to is trying to implement it into BASeBlock. ISerializable was bad enough, but now IXMLSerializable is going to pretty much double the amount of serialization code. I’ve started to graph out the serialization dependencies and what classes or interfaces should derive from or implement the new IXMLSerializable interface. Ideally I’d like to add it to the classes lower in the heirarchy first so that I can use Unit Tests each step along the way to verify that it is working as intended and creating the desired XML output as well as able to reconstitute the class instance. As is I have a few which basically create a object, save it, deserialize to another object and assert that the two are equal. I’ve been bogged down adding a bunch of Framework support such as the aforementioned Image and Point and other types used by BASeBlock which will need to be serialized, but once that is in place (and, again, tested along the way) I’ll be able to start adding IXMLSerializable implementations to each class along the way.

It is currently a class library and I am purposely trying to keep it as decoupled from BASeBlock as possible. Currently it does reference some assemblies not typical of a Class Library such as System.Drawing to add support for serialization of those types. I can imagine that being best implemented with still more class libraries but I don’t want to bog the library down in library management problems. Hopefully it will be more generally useful and I can make it available via Github, hopefully. I’ve not updated my repos there for some time because I uninstalled git due to conflicts with Jaspersoft Studio which drove nuts, though I’ve not had to use Jaspersoft for some time so I might be able to get away with installing git again, and revive the repositories and bring them up to date.

Have something to say about this post? Comment!