I’m working with the DataContractJsonSerializer in Silverlight 4 and would like to deserialize the following JSON:
{
"collectionname":"Books",
"collectionitems": [
["12345-67890",201,
"Book One"],
["09876-54321",45,
"Book Two"]
]
}
Into classes like the following:
class BookCollection
{
public string collectionname { get; set; }
public List<Book> collectionitems { get; set; }
}
class Book
{
public string Id { get; set; }
public int NumberOfPages { get; set; }
public string Title { get; set; }
}
What’s the proper place to extend DataContractJsonSerializer to map the unnamed first array element in “collectionitems” to the Id property of the Book class, the second element to the NumberOfPages property and the final element to Title? I don’t have control over the JSON generation in this instance and would like the solution to work with the Silverlight subset of .NET. It would be great if the solution could perform the reverse for serialization as well.
If this weren’t Silverlight, you could use
IDataContractSurrogateto useobject[](what’s actually present in your JSON) instead ofBookwhen serializing/deserializing. Sadly,IDataContractSurrogate(and the overloads of theDataContractJsonSerializerconstructor which use it) aren’t available in Silverlight.On Silverlight, here’s a hacky but simple workaround. Derive the
Bookclass from a type which imlpementsICollection<object>. Since the type in your serialized JSON isobject[], the framework will dutifully serialize it into yourICollection<object>, which in turn you can wrap with your properties.The easiest (and hackiest) is just to derive from
List<object>. This easy hack has the downside that users can modify the underlying list data and mess up your properties. If you’re the only user of this code, that might be OK. With a little more work, you can roll your own implementation ofICollectionand permit only enough methods to run for serialization to work, and throwing exceptions for the rest. I included code samples for both approaches below.If the above hacks are too ugly for you, I’m sure there are more graceful ways to handle this. You’d probably want to focus your attention on creating a custom collection type instead of
List<Book>for yourcollectionitemsproperty. This type could contain a field of typeList<object[]>(which is the actual type in your JSON) which you might be able to convince the serializer to populate. Then your IList implementation could mine that data into actual Book instances.Another line of investigation could try casting.For example could you implement an implicit type conversion between
Bookandstring[]and would serialization be smart enough to use it? I doubt it, but it may be worth a try.Anyway, here’s code samples for the derive-from-ICollection hacks noted above. Caveat: I haven’t verified these on Silverlight, but they should be using only Silverlight-accessible types so I think (fingers crossed!) it should work OK.
Easy, Hackier Sample
Harder, slightly-less-hacky sample
Here’s the second sample, showing a manual implementation of ICollection, which prevents users from accessing the collection– it supports calling
Add()3 times (during deserialization) but otherwise doesn’t allow modification viaICollection<T>. The ICollection methods are exposed using explicit interface implementation and there are attributes on those methods to hide them from intellisense, which should further reduce the hack factor. But as you can see this is a lot more code.BTW, the first time I read your quesiton I skipped over the important Silverlight requirement. Oops! Anyway, if not using Silverlight, here’s the solution I coded up for that case– it’s much easier and I might as well save it here for any Googlers coming later.
The (on regular .NET framework, not Silverlight) magic you’re looking for is IDataContractSurrogate. Implement this interface when you want to substitute one type for another type when serializing/deserializing. In your case you wnat to substitute
object[]forBook.Here’s some code showing how this works: