Caveats when migrating existing CLSA.NET objects to Silverlight
So you have been working for a while with CSLA .NET by Rockford Lhotka and now you want – like me – jump on the Silverlight bandwagon. So you want to reuse the business objects in Silverlight. There are some nice samples in the cslalight samples but when I started to try to use my own business objects, things did not run so smoothly as the samples suggest.
The samples by Rockford show the general outline:
- You make a second assembly into which you add the exisiting business class source files as a link
- You start adding specific Silverlight functionality surrounded by
#if SILVERLIGHT (…) #endif preprocessor directives - You make sure that the server stuff like data access is not active in the Silverlight configuration (#if !SILVERLIGHT)
- You add a Silverlight-specific factory method to load an object, that looks a bit like this:
public static void Get(int id, EventHandler<DataPortalResult<MyBusinessClass>> callback) { var dp = new DataPortal<MyBusinessClass>( ); dp.FetchCompleted += callback; dp.BeginFetch( new IdCriteria(id) ); }
If you try to call this from your Silverlight client the result is - unless you are very lucky - most likely that the sky starts caving in. Turns out there are a few 'hidden requirements' –or at least some less apparent ones. Maybe there are more, but this was what I found so far:
- Both the Silverlight and the full framework assemblies must have the same name, so even if your projects are called MyLib.Server and MyLib.Client, the resulting dll’s must have the same name, for example MyLib.dll.
- If your full framework assembly is signed, your Silverlight assembly should be signed as well. They then also must have the same version number – all the way to the build number. This is important – and it took me the most time before the penny dropped.
- All the Silverlight classes must have public constructors. So you add
#if! SILVERLIGHT private MyBusinessClass() { } #else public MyBusinessClass() { } #endif
- Properties should be defined in the ‘modern’ format. You have still properties in this format?
private string _oldProp = string.Empty; public string OldProp { get { return _oldProp; } set { if (value == null) value = string.Empty; if (!_oldProp.Equals(value)) { _oldProp = value; PropertyHasChanged("OldProp"); } } }Tough luck. Change that into the 'new' form, e.g.
private static PropertyInfoNewPropProperty = RegisterProperty (c => c.NewProp); public string NewProp { get { return GetProperty(NewPropProperty); } set { SetProperty(NewPropProperty, value); } }
- Criteria objects should have public constructors as well, and should be public classes – that is, if you have defined them as private classes inside your business object, you should make them public
- Your Criteria should implement IMobileObject. The easiest way is to let your class descend from CriteriaBase, but then you will find out that although the class is serialized to the server, the properties are not. Turns out that for Criteria objects the property format has changed too. In the past you could just make a simple class with a few getters and setters, now you have to make something along this line:
[Serializable] public class IdCriteria : CriteriaBase { public static PropertyInfo<int> IdProperty = RegisterProperty(typeof(IdCriteria), new PropertyInfo<int>("Id")); public int Id { get { return ReadProperty(IdProperty); } set { LoadProperty(IdProperty, value); } } public IdCriteria() { } public IdCriteria(int id) { Id = id; } }
So, although CLSA ‘light’ promises a lot of reuse (which is true of course, in the case of business and validation rules) you need a lot of extra plumbing to get going. And mind you, this is a simple single object that I only read – I haven’t covered lists yet, nor updates and deletes. The power of CSLA can come to Silverlight – but certainly for existing libraries it is not quite a free ride. But then again - this is Silverlight, so it should run on Windows Phone 7 series as wel... which will be my next experiment. I will keep you posted!