Sunday, April 13, 2008
« My philosophy on using new technologies | Main | Podcast recapping MIX 08 »

Silverlight 2.0 doesn't have an equivalent to the BinaryFormatter or NetDataContractSerializer. This makes some things quite challenging - in my case building CSLA Light. CSLA .NET requires high-fidelity serialization both for implementation of the Clone() operation and within the data portal.

I've been working on building a Silverlight-compatible equivalent to the BinaryFormatter/NDCS. It turns out to be quite hard due to the limitations of the Silverlight sandbox.

For example, Silverlight does have reflection, even against private fields. However, you can only get or set a private field with code inside the same class as the field declaration. You can't get/set a field from another object, or even from a base class or subclass. The reflection call must be in the same class!

At this point I have a prototype serializer that works in some limited scenarios. It is a starting point. Some aspects aren't ideal, but may just be the way they are to get around how Silverlight works. Still, the end result is relatively cool.

To use the serializer:

  1. Build the Csla project (it is a Silverlight Class Library) and reference it from your Silverlight application
  2. In your business class, add a using/Imports statement for Csla.Serialization
  3. Add the Serializable attribute to your class
  4. You class must also either inherit from MobileObject or implement the IMobileObject interface (I recommend using inheritance, as otherwise you'll have to write a lot of nasty code)
  5. You must override GetValue() and SetValue() in your class - these methods are called by the MobileFormatter so you can reflect against your private fields. See the example below to see how this works
  6. You can now use the MobileFormatter much like you would the BinaryFormatter. See the example below

The MobileFormatter is far from complete. But it can serialize/deserialize fields of an object that contain primitive types (anything that works with Convert.ChangeType()). And it handles references to other serializable objects, both single objects and lists of serializable objects (if they implement IMobileObject or inherit from MobileList<T> ).

I'm pretty sure it can't handle arrays, nor can it handle any list type other than (effectively) List<T>. I'm not sure what it will do with enums or other types - just haven't gotten that far yet.

Here's a serializable object:

using System;
using Csla.Serialization;

namespace SilverlightApplication1
{
  [Serializable]
  public class Person : MobileObject
  {
    #region Serialization

    protected override object GetValue(System.Reflection.FieldInfo field)
    {
      if (field.DeclaringType == typeof(Person))
        return field.GetValue(this);
      else
        return base.GetValue(field);
    }

    protected override void SetValue(System.Reflection.FieldInfo field, object value)
    {
      if (field.DeclaringType == typeof(Person))
        field.SetValue(this, value);
      else
        base.SetValue(field, value);
    }

    #endregion

    public string Name { get; set; }

    [NonSerialized]
    private DateTime _birthdate;
    public DateTime BirthDate
    {
      get { return _birthDate; }
      set { _birthdate = value; }
    } 
  }
}

And here's how to serialize/deserialize the object:

var p = new Person();

var formatter = new Csla.Serialization.MobileFormatter();
var buffer = new System.IO.MemoryStream();
formatter.Serialize(buffer, p);

buffer.Position = 0;
var copyOfP = (Person)formatter.Deserialize(buffer);

Though it is unfortunate that every business class must implement GetValue() and SetValue(), I think that is a relatively small price to pay to get nearly the same capability as we have in .NET with the BinaryFormatter in terms of cloning objects, and more importantly in terms of serializing them across the network with full fidelity.


Monday, April 14, 2008 2:17:01 AM (Central Standard Time, UTC-06:00)
Perhaps you should look into using an AOP library, such as PostShrarp, to inject serialization code into classes after compilng.
Thursday, April 17, 2008 3:52:54 AM (Central Standard Time, UTC-06:00)
Hi,

isn't there any way to use the same business class in Silverlight 2.0 as in windows/web applications?
Anders Sidwall
Friday, April 18, 2008 12:56:14 AM (Central Standard Time, UTC-06:00)
I thought this was supposed to work under SL:
http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx
Dennis
Saturday, April 19, 2008 10:16:59 AM (Central Standard Time, UTC-06:00)
My goal IS to use (much) the same business class in SL2 as in .NET. I doubt 100% reuse is realistic, because SL2 is a subset of .NET, and so some features just aren't there.

The idea of using something like PostSharp is interesting, but I always try to minimize dependencies on external tools, only resorting to their use if absolutely required. One must always weight the cost/risk of a dependency against the cost/risk of solving the problem without the tool. I am not done trying to solve this issue with the abilities available in SL2 itself.

It is true that SL2 has a subset of the DataContractSerializer. However, even the full DCS in .NET doesn't do what I need for the data portal, and the SL2 subset version is _really_ out of the question for this purpose...
Thursday, May 08, 2008 4:06:48 PM (Central Standard Time, UTC-06:00)
I might be missing something, but would wiring up the serializable property support be easier if you just require them to be depedency properties in silverlight? Just thinking that property discovery by object (from a CSLA standpoint) might be more involved, but then everyone is just following the well known DependencyProperty idiom.
Steve
Thursday, May 08, 2008 4:42:20 PM (Central Standard Time, UTC-06:00)
The reason I put the 'managed property' concept into CSLA .NET 3.5 was in anticipation of not having enough reflection in Silverlight to write a serializer. If you look at the managed property scheme, it is similar to the idea of a dependency property. Using actual dependency properties won't solve the problem, because the field storage is not under my control (it is in Microsoft's base class).

And serializing through managed properties is still my fallback position. But if I can get regular fields to serialize without too much work that would provide a higher level of compatibility between business code in CSLA .NET and CSLA Light, and that seems like a really good thing to me.

My problem now is actually less with serializing fields (I have that all working) and more with serializing other complex types like Stack<T>, BindingList<T> and some array types. These flow from some of the .NET base classes I inherit from or use in CSLA .NET - types I don't control - and that is challenging.

The challenge comes ultimately because my serializer is asymmetric - Silverlight on one side and .NET on the other side - and so the types don't necessarily exactly match (there is no BindingList<T> in Silverlight for example). Also the techniques available to DO serialization are different on either side. On Silverlight is very limited reflection, and on the .NET side there's full reflection, but also ISerializable (which is very complex, and which I'm avoiding thus far).
Comments are closed.