Wednesday, April 23, 2008
« Free Comic Book Day 2008 | Main | CSLA .NET Master Class training »

I spent some time over the past few days using my prototype Silverlight serializer to build a prototype Silverlight data portal. It is still fairly far from complete, but at least I've proved out the basic concept and uncovered some interesting side-effects of living in Silverlight.

The good news is that the basic concept of the data portal works. Defining objects that physically move between the Silverlight client and a .NET web server is practical, and works in a manner similar to the pure .NET data portal.

The bad news is that it can't work exactly like the pure .NET data portal, and the technique does require some manual effort when creating the business assemblies (yes, plural).

The approach I'm taking involves having two business assemblies (VS projects) that share many of the same code files. Suppose you want to have a Person object move between the client and server. You need Person in a Silverlight class library and in a .NET class library. This means two projects are required, even if they have the same code file.

Visual Studio makes this reasonable, because you can create the file in one project (say the Silverlight class library) and then Add Existing Item and use the Link feature to get that same file included into a .NET class library project.

I also make the class be a partial class, so I can add extra code to the .NET class library implementation. The result is:

BusinessLibrary.Client (Silverlight class library)
  -> Person.cs

BusinessLibrary.Server (.NET class library)
  -> Person.cs (linked from BusinessLibrary.Client)
  -> Person.Server.cs

One key thing is that both projects build a file called BusinessLibrary.dll. Also, because Person.cs is a shared file, it obviously has the same namespace. This is all very important, because the serializer requires that the fully qualified type name ("namespace.type,assembly") be the same on client and server. In my case it is "BusinessLibrary.Person,BusinessLibrary".

The Person.Server.cs file contains the server-only parts of the Person class - it is just the rest of the partial class. The only catch here is that it can not define any fields because that would obviously confuse the serializer since those fields wouldn't exist on the client. Well, actually it could define fields as long as they were marked as NonSerialized.

Of course you could also have a partial Person.Client.cs in the Silverlight class library - though I haven't found a need for that just yet.

One thing I'm debating is whether the .NET side of the data portal should just directly delegate Silverlight calls into the "real" data portal - effectively acting as a passive router between Silverlight and the .NET objects. OR the .NET side of the data portal could invoke specific methods (like Silverlight_Create(), Silverlight_Update(), etc) so the business developer can include code to decide whether the calls should be processed on the server at all.

The first approach is simple, and certainly makes for a compelling story because it works very much like CSLA today. The Silverlight client gets/updates objects in a very direct manner.

The second approach is a little more complex, but might be better because I'm not sure you should blindly trust anything coming from the Silverlight client. You can make a good argument that Silverlight is always outside the trust boundary of your server application, so blindly passing calls from the client through the data portal may not be advisable.

Either way, what's really cool is that the original .NET data portal remains fully intact. This means that the following two physical deployment scenarios are available:

Silverlight -> Web server -> database
Silverlight -> Web server -> App server -> database

Whether the web/app server is in 2- or 3-tier configuration is just a matter of how the original .NET data portal (running on the web server) is configured. I think that's awesome, as it easily enables two very common web server configurations.

The big difference in how the Silverlight data portal works as compared to the .NET data portal is on the client. In Silverlight you should never block the main UI thread, which means calls to the server should be asynchronous. Which means the UI code can't just do this:

var person = Person.GetPerson(123);

That sort of synchronous call would block the UI thread and lock the browser. Instead, my current approach requires the UI developer to write code like this:

var dp = new Csla.DataPortal();
dp.FetchCompleted +=
  new EventHandler<Csla.DataPortalResult<Person>>(dp_FetchCompleted);
dp.BeginFetch<Person>(new SingleCriteria<int>(123));

with a dp_FetchCompleted() method like:

private void dp_FetchCompleted(object sender, Csla.DataPortalResult<Person> e)
{
  if (e.Error != null)
    // e.Error is an exception - deal with the issue
  else
    // e.Object is your result - use it
}

So the UI code is more cumbersome than in .NET, but it follows the basic service-calling technique used in any current Silverlight code, and I don't think it is too bad. It isn't clear how to make this any simpler really.


Wednesday, April 23, 2008 5:17:02 PM (Central Standard Time, UTC-06:00)
Great news, Rocky! It is so encouraging to know that serialization and the data portal for Silverlight are becoming a reality. This is so awesome!

Chris
Chris
Thursday, April 24, 2008 3:00:25 AM (Central Standard Time, UTC-06:00)
Alexandria?
David
Thursday, April 24, 2008 5:14:33 AM (Central Standard Time, UTC-06:00)
Are you using the dispatcher to ensure that the callback happens on the UI thread?
Dennis
Thursday, April 24, 2008 7:41:24 AM (Central Standard Time, UTC-06:00)
Nice. When can we see the first release?

Thomas
Thursday, April 24, 2008 2:14:06 PM (Central Standard Time, UTC-06:00)
Dennis, I am actually allowing WCF to call the dispatcher, but yes, the callback is on the UI thread.
Monday, April 28, 2008 1:25:45 AM (Central Standard Time, UTC-06:00)
It should be unnessesary to split up your logic in two files. The Silverlight projects automatically define the Constant SILVERLIGHT, so you can put your code in #if's

#if !SILVERLIGHT
dataportmethods.
#endif

MSBuild does have an import task to include all build targets from another project, however it complains when trying to use it between two projects where one is a silverlight and the other is not.
Dennis
Monday, April 28, 2008 7:02:10 AM (Central Standard Time, UTC-06:00)
Dennis, that is not entirely true, unless you know of a way to fix the references. The Silverlight business project references any number of Silverlight assemblies. The .NET business project references any number of .NET assemblies.

I am not aware of a way to put conditional compilation statements around the reference blocks and have a project compile twice (once for Silverlight and once for .NET) - but if that is possible, and isn't ridiculously painful compared to my current (pretty painless) approach then it might make sense.
Monday, April 28, 2008 8:58:43 AM (Central Standard Time, UTC-06:00)
MSBuild files has support for conditionally including some part depending on an option set elsewhere, just have to do it manually rather than rely on VS to do the work for you.
Still need two project files where one includes the other, however it currently doesn't work because of a restriction to not include non-silverlight libraries in silverlight libraries.
If I have some time I will try to hack together a msbuild task to make it less painless (ie. not manual changes in the non-silverlight csproj file). Then developers only have deal with the references in the two projects, but act as if the files just exists in one and happens to get compiled twice. One time being with SILVERLIGHT defined.
Dennis
Monday, May 05, 2008 8:33:14 PM (Central Standard Time, UTC-06:00)
Hi Rocky,

Kept waiting for the big flashing yellow "Warning - Security Risk" signs but they never appeared.

I'd recommend pointing out that _anything_ that goes to the client in Silverlight can ultimately be disassembled (ie. Reflector) so developers should be sure their CSLA business objects are appropriate candidates.
Adrian Lanning
Monday, May 05, 2008 10:09:57 PM (Central Standard Time, UTC-06:00)
Adrian, I'm sure I'll get to the point of worrying about best practices - after I have something to actually practice with :)
Wednesday, May 07, 2008 1:47:22 PM (Central Standard Time, UTC-06:00)
I like your approach Rockford, as the data access code ain't distributed to the clients. I think that not being able to disassemble the application server code is a good security enhancement. Is it possible to use the same approach for CSLA.NET as of today?
Espen Røvik Larsen
Sunday, May 11, 2008 2:04:28 PM (Central Standard Time, UTC-06:00)
I'm very much looking forward to this; like my friend Adrian said, security is a big issue in my mind with Silverlight and because of that I'm in favor of the the Silverlight hitting a layer before it it's the data portal - however keeping it 'transparent' and 'simple' is going to be the hard part - obviously anytime you add a layer you add complexity, but if it's minimal, I think it should be fairly well accepted.

I'm also in favor of the partial classes and linked classes - this is a heck of a lot easier for the Morts to understand than dynamic compliations and flags in MSBuild (so many rely on F5 for everything).

I have one request though - I know you've been using Project Tracker forever now; but I think just like Adventure Works replaced Northwind, I think it's time for Project Tracker to be retired, I have a hard time relating it, or selling it to non-CSLA people.
Brian Johnston
Monday, June 02, 2008 11:37:23 AM (Central Standard Time, UTC-06:00)
Speaking of WPF when will your "WPF and business objects demo (MagenicCV)" that you did at DevConnections in November of 2007 be available to download? It was a really cool demo.
Comments are closed.