Thursday, July 17, 2008

If you've tried to do any unit testing in Silverlight, you may have run into an interesting issue. Many times, unit tests expect exceptions. Tests are written to ensure that an exception occurs as expected. That's a standard concept in most unit testing frameworks for .NET.

In Silverlight, there's an "expected CLR behavior" where the debugger will break on exceptions that are actually handled by user code - treating them like they aren't handled. See this thread for some more detail:

http://silverlight.net/forums/p/20678/72377.aspx#72377

The result of this, is that you have to employ some ugly workarounds, or you need to press F5 for each of your tests where you expect an exception.

We're running into this issue in a big way with CSLA Light (CSLA .NET for Silverlight), because we're creating lots and lots of unit tests, and a fair number of them are testing to make sure exceptions occur when we expect them.

Of course our unit testing framework (UnitDriven) uses reflection to run each test method - just like MSTest or nunit - and so even though we are handling the exception in user code the debugger insists on breaking in the test methods themselves where the exceptions occur.

Again, there are workarounds. They prevent you from using the debugger to walk through your tests - but at least they exist. The whole thing is really sad though - given that this is apparently intended behavior.

Thursday, July 17, 2008 10:44:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  | 

 Tuesday, July 15, 2008

I have put a very early preview release of CSLA Light and CSLA .NET 3.6 online at www.lhotka.net/cslalight/download.aspx.

There is no sample app at this point, so you'll have to look at the unit tests in cslalighttest and cslatest to figure out how to use the various features.

Obviously this is very early code, but it is healthy to release early and often, so here we go :)

One side-effect of our work with CSLA Light is that we discovered that testing asynchronous methods is really hard with nunit and MSTest, and impossible with the Silverlight unit test framework provided by Microsoft. And yet in Silverlight, async methods are commonly required, and for parity a number of async features are now also in CSLA .NET. And we need to have unit tests for them.

To address this issue, we ended up creating our own Silverlight unit testing framework, and an add-on framework for nunit or MSTest. This allows us to write a common set of test code that runs in both Silverlight and .NET so we can test both, and establish that we have parity between them.

Earier today, Justin split this testing framework out of CSLA and we put it up on CodePlex, calling it UnitDriven. The CSLA Light project and Magenic are donating the code to the community as an open-source project, because it can be used to build async unit tests for any app, not just for CSLA Light.

Tuesday, July 15, 2008 6:40:52 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  | 

 Monday, July 14, 2008

While most people use CSLA .NET because it provides support for data binding, validation, business rules and authorization, I personally think the coolest part of the framework is its support for mobile objects. This support is provided by the data portal, which provides both an abstract persistence model for business objects, as well as an implementation of mobile objects with location and network transparency.

CSLA Light will also include a data portal that works in a manner similar to the one in CSLA .NET. In fact, the two are complimentary - the CSLA Light data portal talks to the CSLA .NET data portal, because the client is running Silverlight and the server is running .NET. This occurs when the CSLA Light data portal is running in "remote" mode - meaning it is talking to a remote data portal server.

The CSLA Light data portal can also run in "local" mode, which means that the "data access" code runs on the Silverlight client. In reality, this probably means that your client-side code is directly calling some external service - an asmx web service, a WCF service, ADO.NET data services, etc. So the fact is that the data access is still on some server somewhere, but you aren't using the data portal to get from the client to that server.

As in .NET, when using the data portal in local mode things are pretty simple. A call to the data portal to fetch an object simply results in a call to a DataPortal_Fetch() method in your object, and the object is running on the client in Silverlight. What you do in that DataPortal_Fetch() method is entirely up to you, as long as the object is populated with data by the time the call completes.

When you use the remote data portal there are more options. Things are somewhat different from the existing .NET data portal. The following figure will help explain.

image

The CSLA Light data portal interacts with a server (probably a web server, though it could be a Windows Server 2008 running WAS) through WCF. That server is running CSLA .NET 3.6, which includes data portal support to listen for CSLA Light data portal requests. Objects are serialized to/from CSLA Light using the MobileFormatter, which is a serializer included in both CSLA Light and CSLA .NET that provides a subset of the functionality provided by the BinaryFormatter (or NetDataContractSerializer), targeted at the CSLA scenario.

On the web server, CSLA .NET 3.6 receives the inbound client request. Any objects sent from the client to the server are deserialized (including any criteria objects or business objects). At this point there are two ways the process will work.

The default option is that the call from the client is "echoed" into the standard CSLA .NET data portal. In other words, if the client calls Fetch() on the data portal, that call is relayed into the standard data portal as a Fetch() request. This means that the .NET data portal applies its normal process and runs in local or remote mode and ultimately creates an instance of your business object and calls its DataPortal_Fetch() method. Remember that this is all happening in .NET on the server(s). The resulting business object is then returned through the .NET data portal to the web server, and from there through the Silverlight data portal to the client.

So by default, the .NET data portal running on the web server (in the diagram) is a pass-through from Silverlight into .NET. The end result is that the Silverlight data portal works just like the .NET data portal does today.

While the default is good and easy, it may not always be ideal. You may not trust the code running in Silverlight on the client. You may be concerned that the code has been compromised, that somehow a malicious user cracked into the Silverlight runtime, mucked around with your code and bypassed your logic. Thus far no one has established that this can be done, but I can understand the concern.

In that case, another option is that the business class (on the .NET side) can have a MobileFactory attribute attached:

[MobileFactory("MyLibrary.CustomerFactory,MyLibrary", "Create", "Fetch", "Update", "Delete")]
public class Customer : BusinessBase<Customer>

If this attribute is applied, the .NET data portal will create an instance of the type specified in the attribute, and will call methods on that factory object instead of on the business object. In other words, a call that would have gone to DataPortal_Fetch() will now go to a method matching the third parameter of the attribute - in this example a method called Fetch().

The factory object is responsible for creating, initializing and returning the object from create/fetch/update operations. Delete returns nothing. How the factory object does this is up to the factory author - you. I suspect a very common implementation will be for the factory method to do extra business checks (validation/authorization) to decide if the client call is valid, and if it is valid then the factory will just echo the call into the .NET data portal. So you might write something like this in a factory:

public object Fetch(SingleCriteria<Customer, int> criteria)
{
  // do extra validation/authorization checks here
  if (allChecksPassed)
    return DataPortal.Fetch(criteria);
  else
    throw new Exception("Bad client request");
}

A colleague of mine at Magenic, Nermin Dibek, suggested an interesting enhancement to this MobileFactory model, which I'll include in the implementation. As a configuration option, you can specify a "factory of factories" object. The default behavior is to take the type name in the first parameter and use it to create an instance of the factory object. But if you'd like, you can create your own "factory creator" object that takes that first parameter and uses it however you'd like to create an instance of the factory. This would allow you to substitute MyTestLibrary for MyLibrary when you wanted to use a set of test factories instead of the production versions, and that sort of thing.

It is my intent to extend this MobileFactory concept into the .NET data portal itself (in CSLA .NET 3.6), so in a pure-.NET scenario you'd have comparable options, like this figure:

image

The data portal would default to its existing behavior, which would be unchanged. However, you'd be able to apply an ObjectFactory attribute to your business classes to indicate that the data portal should route its calls to your factory object rather than to the DataPortal_XYZ methods.

The only catch here, is that your factory objects then assume responsibility for managing the status values (IsNew, IsDirty, etc) of the object (and its child objects, etc). The data portal essentially steps out of the picture entirely - leaving you to do all the work of creating and manipulating the business object as necessary. However, this does open up some interesting alternatives for persisting objects even though the solution is less automated than the current implementation.

The CSLA Light part of what I've discussed here is in the current 3.6 code in Subversion (svn://svn.lhotka.net/csla/branches/cslacs36 and svn://svn.lhotka.net/csla/trunk/cslalightcs). The ObjectFactory support for CSLA .NET itself will probably happen in a few weeks.

Monday, July 14, 2008 9:41:52 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  | 

 Tuesday, June 24, 2008

With serialization largely out of the way - or at least under control - as described in a recent blog post, we've been able to put some focus on a couple other key areas.

N-Level Undo

The n-level undo functionality in CSLA .NET relies on reflection against private fields. Obviously that's not possible in Silverlight. Fortunately the serialization scheme we're using means that there's already a mechanism for trapping the values stored in the field manager. And there's the OnGetState()/OnSetState() methods that allow a business developer to trap/restore values in their private fields (if they choose). So UndoableBase had to be altered to use these techniques rather than using reflection. The end result is the same, which is what really matters.

We opted not to replicate IEditableObject into CSLA Light. It is a .NET interface used by Windows Forms data binding, and is the source of never-ending pain thanks to all the edge cases and idiosyncrasies around this, seemingly simple, interface. Of course the interface isn't used by Silverlight (or WPF), and so isn't necessary. The effect of this choice is to simplify quite a bit of the n-level undo code, while at the same time preserving the shape of the pre-existing public interface for all objects. In other words, BeginEdit(), CancelEdit() and ApplyEdit() work as expected, but you can't use IEditableObject to get at its versions of those methods.

Justin just ran into a strange issue with BusinessListBase, where an attempt to iterate through the items in the list caused a strange runtime exception from somewhere deep in the bowels of the Silverlight runtime. It appears there's some issue with a subclass of a collection iterating through its own items in a foreach loop. A for loop works fine however, so we have a workaround.

Ultimately however, the ability to easily implement a Cancel button, including when using modal dialogs (which can be simulated in Silverlight) is supported

Data Portal

The data portal is coming along pretty well too. It supports a provider model, conceptually similar to the data portal in .NET. And we currently have two providers: local and WCF.

One issue we're facing here is that Silverlight has no configuration subsystem comparable to System.Configuration. So there's no easy way to get configuration data from an "app.config" file or equivalent. At the moment I've come up with a code-based configuration scheme - but (unless Microsoft puts out a solution soon) we'll probably end up creating some embedded resource-based configuration subsystem of our own.

The data portal itself is asynchronous. This changes the way the UI code interacts with the data portal when compared to .NET code. Rather than just calling DataPortal.Fetch() to get an object, in Silverlight the UI must call a BeginFetch() method to start the process and handle a completed event to process any results when they return.

This means the UI code looks something like this:

var dp = new DataPortal<MockEditableRoot>();
dp.FetchCompleted += new EventHandler<DataPortalResult<MockEditableRoot>>(dp_FetchCompleted);
dp.BeginFetch();

This code starts the process, and the dp_FetchCompleted is invoked (on the UI thread) when the call is complete:

private void dp_FetchCompleted(object sender, DataPortalResult<MockEditableRoot> e)
{
  this.DataContext = e.Object;
}

Alternately you can wrap this code into a factory method and completed event provided by the business class. That is a little closer to the typical CSLA .NET model - but is still async, and the UI still must handle the result in a callback event handler.

Local Data Portal

When using the data portal in local mode, it calls DataPortal_XYZ methods, much like the .NET data portal. There are a couple interesting differences however. The first being that the DataPortal_XYZ methods must be public in scope. Remember, no private reflection, so only public methods can be called.

I debated about using an interface-based approach, but decided against it for a couple reasons. First, it would be dissimilar to the existing .NET approach. Second, it would mean that your DataPortal_XYZ methods couldn't be strongly typed - they'd have to accept parameters of type object and you'd have to cast them to something meaningful.

The second difference flows from the fact that most server-related activities in Silverlight are asynchronous. Most DataPortal_XYZ methods, therefore, will be invoking async server calls and getting the results from a callback event. So all DataPortal_XYZ methods are provided a delegate they can use to do a callback to indicate completion. In a simple (synchronous) example it looks like this:

public void DataPortal_Insert(
  Csla.DataPortalClient.LocalProxy<MockEditableRoot>.CompletedHandler handler)
{
  LoadProperty<string>(DataPortalMethodProperty, "insert");
  handler(this, null);
}

The DataPortal_Insert() method accepts a CompletedHandler parameter it can use to indicate completion. The call to handler() is the completion call, and the first parameter is the resulting business object, while the second is an Exception object if you want to indicate failure.

In an asynchronous example things are a bit more complex. And the async scenario is the most common. Typically when using a "local" data portal you'd be doing so because you want to call some web service or data service from Silverlight. And since all the server call technologies in Silverlight are async, your DataPortal_XYZ method will almost certainly be invoking some async service. So more normal code might look like this:

public void DataPortal_Insert(
  Csla.DataPortalClient.LocalProxy<MockEditableRoot>.CompletedHandler handler)
{
  var svc = new Csla.Testing.Business.TestService.TestServiceClient();
  svc.InsertDataCompleted +=
    new EventHandler<Csla.Testing.Business.TestService.InsertDataCompletedEventArgs>
      (svc_InsertDataCompleted);
  svc.InsertData(GetProperty<string>(DataPortalMethodProperty), handler);
}

void svc_InsertDataCompleted(
  object sender, Csla.Testing.Business.TestService.InsertDataCompletedEventArgs e)
{
  var handler = (Csla.DataPortalClient.LocalProxy<MockEditableRoot>.CompletedHandler)e.UserState;
  handler((MockEditableRoot)e.Result, e.Error);
}

This looks a bit odd, but after you do a bit of Silverlight programming this pattern becomes second nature.

The DataPortal_XYZ method sets up and starts the call - passing parameters to the service, and one parameter that is "user state", which is extra (doesn't go to the server, but stays on the client). Notice that before making the InsertDataAsync() call, which is the call to the service, the code hooks the InsertDataCompleted event - this is the event that will be raised (on the UI thread) when the service call completes.

The svc_InsertDataCompleted() method is the event handler. This is where you write the code to handle the results from the service call. When using the data portal, this is where you call back into CSLA to indicate that the call is complete. Ultimately CSLA will return the result to the UI code, but this mechanism allows CSLA to do any extra processing between the DP_XYZ call and the UI so it can manage the state of your business object.

You can also shrink this by using a lambda:

public void DataPortal_Insert(
  Csla.DataPortalClient.LocalProxy<MockEditableRoot>.CompletedHandler handler)
{
  var svc = new Csla.Testing.Business.TestService.TestServiceClient();
  svc.InsertDataCompleted += (o, e) => { handler((MockEditableRoot)e.Result, e.Error); };
  svc.InsertDataAsync(GetProperty<string>(DataPortalMethodProperty));
}

That eliminates the need for a separate event handler method and simplifies the code.

Remote Data Portal

The remote data portal option works very much like the normal .NET data portal, and is generally simpler to use that the local data portal. When the data portal is configured to use the WcfProxy, it will use WCF to communicate with a CSLA .NET data portal on the web/app server.

In this scenario you need a web or app server that is hosting a CSLA .NET data portal - the .NET end of the CSLA Light data portal. The CSLA Light code running on the Silverlight client will call the CSLA .NET code running on the app server.

When using a remote data portal, the Silverlight business object will not include any DataPortal_XYZ methods. The DataPortal_XYZ methods will only be implemented in the .NET code, and will only exist on the server. The client-side code will still call the data portal, but the call will be automatically routed through WCF to the app server.

This is exactly the same kind of behavior you'd get from the existing .NET data portal - you can choose to use a local or remote data portal, but the business object and UI code are the same either way (with the exception that a local data portal requires implementation of DataPortal_XYZ methods).

On the app server, which is running CSLA .NET, requests will come in from the Silverlight client. These requests can be handled in one of two ways.

The default is for the client call to be routed into the CSLA .NET data portal, and the rest of the processing is normal CSLA .NET processing. In other words, a Silverlight Fetch() call results in a DataPortal.Fetch() call on the app server, which runs the DataPortal_Fetch() method just like it always has. The result of the data portal call on the app server is then returned to the Silverlight client.

I call that the "pass-through" mode because the server-side data portal just passes the client call through to the "real" data portal. And this is a great option for when you trust the client that is running the Silverlight app, because it requires the least amount of code and provides the simplest solution.

But if you don't trust the Silverlight client. If you are worried that someone will break into the Silverlight runtime and somehow put bad data into your object's fields (perhaps bypassing your business logic, etc), then extra precautions are required. To address that concern, the server-side data portal can optionally invoke an "observer" or "factory" (I'm still debating the name of this thing).

To do this, on your server-side business object code (in the server-only partial class) you use the MobileFactory attribute to specify the type name of the factory object, and the method names to be called for create, fetch, update and delete operations (the only operations the data portal supports).

[MobileFactory("MyProject.MyFactory, MyProject", "Create", "Fetch", "Update", "Delete")]
public partial class MockEditableRoot

Then you must implement the factory class:

public class MyFactory
{
  public object Create(object criteria)
  {
    // create, initialize and return new object here
  }

  public object Fetch(object criteria)
  {
    // create, load and return object here 
  }

  public object Update(object inbound)
  {
    // insert, update or delete object here
    // return resulting object
  }

  public void Delete(object criteria)
  {
    // delete object here 
  }
}

The criteria or business object from the client does materialize on the server. Of course on the server it materializes within code you control, and so you can safely interact with the object from within the methods of this factory. Here, you can force re-running of the validation rules, apply extra authorization rules or other processing you see fit - all on the app server. Only if you are happy with the object would you then invoke the "real" data portal to actually allow the persistence to occur.

Tuesday, June 24, 2008 10:24:09 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  | 

 Monday, June 23, 2008

A couple people have suggested that I might be abandoning VB. Not so!

My first love was Pascal - VAX Pascal actually, which was more like Modula II in many ways. What an awesome language!

My next love was VAX Basic. Now that VB has structured exception handling in .NET, it has finally caught up to where VAX Basic was in the early 90's. No kidding.

Of course after VAX Basic came VB.

And after VB came .NET. I love .NET. I love .NET with VB and C#. C# is just VB with semi-colons, but VB is just C# without semi-colons too. I gave up on the silly language war thing a couple years ago, and am happy to let either or both language live or die by the hand of its users. The language thing was distracting me from truly enjoying .NET.

When it comes to writing books, it is really important to remember that they fund CSLA .NET. As much as I love what I do, I've got kids that will go to college in the (scarily near) future, so I can't work for free. So when I write a book, I can't ignore that C# books outsell VB books around 3:1 (it used to be 2:1, but the market has continued to shift). I still think it is worth writing a VB edition to get that 25% of the market, but you must admit that it makes a lot of sense to go for the 75% first!

It takes several weeks to port a book from one language to the other. The current plan for Expert 2008 Business Objects in C# is October (though I fear that may slip), and with the conversion time and publication schedule constraints, that pushes the VB edition into early 2009. Apress just hasn't put the VB book on their public release list yet, but that doesn't mean I don't plan to do that edition.

When it comes to CSLA Light, I'm doing it in C# because of the 3:1 split, and so again am focusing on C# first.

Whether I do a VB version of the framework or not depends on whether I decide to write a book on the creation and design of CSLA Light. I may or may not. If I don't write a book on the design of the actual framework, I won't port (and then maintain) the framework into a second language.

It is a ridiculous amount of work to maintain CSLA .NET twice, and I really don't like the idea of maintaining CSLA Light twice too. You have no idea how much writing, testing and debugging everything twice slows down progress (and eliminates fun). As wonderful as Instant C# and Instant VB are, the dual effort is a continually increasing barrier to progress.

I might write an ebook on using CSLA Light, in which case I'd leave the framework in C#, but create reference apps in both VB and C# so I can do both editions of the ebook. I think this is the most likely scenario. Certainly VB-compatibility has shaped a couple CSLA Light design decisions already - I won't allow a design that precludes the use of VB to build a CSLA Light app.

(The lack of multi-line lambdas and/or anonymous delegates in VB is a real barrier though... Worse even, than the poor way C# handles implementation of interfaces...)

In the end though, like all of us, I need to be where the market is vibrant. Where I can make money from my hard work. Just now, there's more money to be had from C# content and so that takes priority. But there are a lot of people using VB, and (assuming the sales ratio doesn't slip further) in my view it is worth producing content in the VB space as well.

Monday, June 23, 2008 9:18:31 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [8]  | 

 Saturday, June 14, 2008

We're nearly done with the final serialization implementation. At this point it is possible to clone objects on Silverlight and on .NET using the same MobileFormatter. By extension, this means that objects can be cloned from Silverlight to .NET and visa versa, though we don't have tests for that yet. (and there's a bunch of cleanup and detail work to be done for completeness - but the core engine is there and working)

The approach we've taken is automatic for managed backing fields in a subclass of BusinessBase or ReadOnlyBase. It is also automatic for BusinessListBase, ReadOnlyListBase, etc. It is not automatic for custom criteria classes, but is automatic for SingleCriteria.

The approach does allow for serialization of private backing fields, as long as you override a couple methods in your business class to get/set the field values. This is quite comparable to the PropertyBag scheme from VB6, and is conceptually similar to implementing ISerializable (though not the same due to some required features that aren't in Silverlight - there's a reason Microsoft didn't implement something like the BinaryFormatter).

What this means is that when using only managed backing fields, you have to do no work at all. Your objects will just serialize. If you are using one or more private backing fields you need to do something like this:

namespace MyApp
{
  [Serializable]
  public class CustomerEdit : BusinessBase<CustomerEdit>
  {
    protected override void OnGetState(SerializationInfo info)
    {
      base.GetState(info);
      info.AddValue("MyApp.CustomerEdit._id", _id);
      info.AddValue("MyApp.CustomerEdit._name", _name);
    }

    protected override void OnSetState(SerializationInfo info)
    {
      base.SetState(info);
      _id = info.GetValue<int>("MyApp.CustomerEdit._id";
      _name = info.GetValue<string>("MyApp.CustomerEdit._name");
    }
  }
}

Assuming, of course, that you have two private backing fields, _id and _name. The one important restriction is that the types of all fields must be primitive types, or types that can be coerced using Csla.Utilities.CoerceValue() (which means the value can be converted to/from a string as required by the DataContractSerializer).

Of course if you have a field value that can't be automatically converted to/from a string, you can do the conversion yourself in the OnGetState/OnSetState methods.

This will get a little more complex when we implement UndoableBase (which is the next item on the list), because your overrides must differentiate between "NonSerialized" and "NotUndoable" fields - by hand of course. I expect the final result will look more like this:

namespace MyApp
{
  [Serializable]
  public class CustomerEdit : BusinessBase<CustomerEdit>
  {
    protected override void OnGetState(SerializationInfo info, StateModes mode)
    {
      base.GetState(info);
      if (mode == StateModes.Serialization)
        info.AddValue("MyApp.CustomerEdit._id", _id);
      info.AddValue("MyApp.CustomerEdit._name", _name);
    }

    protected override void OnSetState(SerializationInfo info, StateModes mode)
    {
      base.SetState(info);
      if (mode == StateModes.Serialization)
        _id = info.GetValue<int>("MyApp.CustomerEdit._id";
      _name = info.GetValue<string>("MyApp.CustomerEdit._name");
    }
  }
}

The StateModes enum will have two values: Serialization and Undo. This will allow you to exclude certain fields that are serialization-only or perhaps undo-only. I think this is an edge case for the most part, but the option will be there.

Child objects in CSLA .NET 3.5 and later should always be kept in managed backing fields, and so will be handled automatically. If you have a pressing need to store a child object reference in a private backing field, there are also OnGetChildren() and OnSetChildren() methods you can override. The code is slightly more complex, but is very prescriptive (you either do it right or it won't work :) ) - but I see this as an edge case too, and so I'm not worried if it is a little more complex.

On the whole I'm pretty pleased with this approach. It automates as many cases as can be automated without using reflection, but provides a great deal of extensibility and flexibility for those who don't want to use managed backing fields.

Saturday, June 14, 2008 8:58:12 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  | 

 Tuesday, June 10, 2008

I've been prototyping various aspects of CSLA Light (CSLA for Silverlight) for some time now. Enough to be confident that a decent subset of CSLA functionality will work just fine in Silverlight - which is very exciting!

The primary area of my focus is serialization of object graphs, and I've blogged about this before. This one issue is directly on the critical path, because a resolution is required for the data portal, object cloning and n-level undo.

And I've come to a final decision regarding object serialization: I'm not going to try and use reflection. Silverlight turns out to have some reasonable support for reflection - enough for Microsoft to create a subset of the WCF DataContractSerializer. Unfortunately it isn't enough to create something like the BinaryFormatter or NetDataContractSerializer, primarily due to the limitations around reflecting against non-public fields.

One option I considered is to say that only business objects with public read-write properties are allowed. But that's a major constraint on OO design, and still doesn't resolve issues around calling a property setter to load values into the object - because object setters typically invoke authorization and validation logic.

Another option I considered is to actually use reflection. I discussed this in a previous blog post - because you can make it work as long as you insert about a dozen lines of code into every class you write. But I've decided this is too onerous and bug-prone. So while reflection could be made to work, I think the cost is too high.

Another option is to require that the business developer create a DTO (data transfer object) for each business object type. And all field values would be stored in this DTO rather than in normal fields. While this is a workable solution, it imposes a coding burden not unlike that of using the struct concepts from my CSLA Classic days in the 1990's. I'm not eager to repeat that model...

Yet another option is to rely on the concept of managed backing fields that I introduced in CSLA .NET 3.5. In CSLA .NET 3.5 I introduced the idea that you could choose not to declare backing fields for your properties, and that you could allow CSLA to manage the values for you in something called the FieldManager. Conceptually this is similar to the concept of a DependencyProperty introduced by Microsoft for WF and WPF.

The reason I introduced managed backing fields is that I didn't expect Silverlight to have reflection against private fields at all. I was excited when it turned out to have a level of reflection, but now that I've done all this research and prototyping, I've decided it isn't useful in the end. So I'm returning to my original plan - using managed backing fields to avoid the use of reflection when serializing business objects.

The idea is relatively simple. The FieldManager stores the property values in a dictionary (it is actually a bit more complex than that for performance reasons, but conceptually it is a dictionary). Because of this, it is entirely possible to write code to loop through the values in the field manager and to copy them into a well-defined data contract (DTO). In fact, it is possible to define one DTO that can handle any BusinessBase-derived object, and other for any BusinessListBase-derived object and so forth. Basically one DTO per CSLA base class.

The MobileFormatter (the serializer I'm creating) can simply call Serialize() and Deserialize() methods on the CSLA base classes (defined by an IMobileObject interface that is implemented by BusinessBase, etc.) and the base class can get/set its data into/out of the DTO supplied by the MobileFormatter.

In the end, the MobileFormatter will have one DTO for each business object in the object graph, all in a single list of DTOs. The DataContractSerializer can then be used to convert that list of DTOs into an XML byte stream, as shown here:

image

The XML byte stream can later be deserialized into a list of DTOs, and then into a clone of the original object graph, as shown here:

image

Notice that the object graph shape is preserved (something the DataContractSerializer in Silverlight can't do at all), and that the object graph is truly cloned.

This decision does impose an important constraint on business objects created for CSLA Light, in that they must use managed backing fields. Private backing fields will not be supported. I prefer not to impose constraints, but this one seems reasonable because the alternatives are all worse than this particular constraint.

My goal is to allow you to write your properties, validation rules, business rules and authorization rules exactly one time, and to have that code run on both the Silverlight client and on your web/app server. To have that code compile into the Silverlight runtime and the .NET runtime. To have CSLA .NET and CSLA Light provide the same set of public and protected members so you get the same CSLA services in both environments.

By restricting CSLA Light to only support managed backing fields, I can accomplish that goal without imposing requirements for extra coding behind every business object, or the insertion of arcane reflection code into every business class.

Tuesday, June 10, 2008 8:01:50 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  | 

 Wednesday, April 23, 2008

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 8:08:36 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [13]  | 

 Sunday, April 13, 2008

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.

Sunday, April 13, 2008 7:42:40 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  | 

 Sunday, March 09, 2008

I'm just back from the MIX 08 conference. This was the first conference I've attended in many years (around 10 I think) where I wasn't speaking or somehow working. I'd forgotten just how fun and inspiring it can be to simply attend sessions and network with people in the open areas. No wonder people come to conference!! :)

Not that it was all fun and games. I did have meetings with some key Microsoft people and Scott Hanselman interviewed me for an upcoming episode of Hanselminutes (discussing the various data access and ORM technologies and how they relate to CSLA .NET 3.5).

The Day 1 keynote was everything I'd hoped for.

Well, nearly. The first part of the keynote was Ray Ozzie trying to convey how Microsoft and the web got to where it is now. The goal was to show the vision they are pursuing now and into the future, but I thought the whole segment was rather flat.

But then Scott Guthrie came on stage and that was everything you could hope for. Scott is a great guy, and his dedication and openness seem unparalleled within Microsoft. I remember first meeting him when ASP.NET was being unveiled. At that time he seemed so young and enthusiastic, and he was basically just this kick-ass dev who'd created the core of something that ultimately changed the Microsoft world. Today he seems nearly as young and easily as enthusiastic, and he's overseeing most of the cool technologies that continue to change the Microsoft world. Awesome!

So ScottGu gets on stage and orchestrates a keynote that really illustrates the future of the web. Silverlight (which makes me SOOoooo happy!), IE8, new data access technologies (like we needed more, but they are still cool!) and things like ASP.NET MVC and more.

As I expected, they released a whole lot of beta code. You can get a full list with links from Tim Sneath's blog. He also has links to some getting started materials.

The real reason for keynotes though, is to inspire. And this keynote didn't disappoint. The demos of Silverlight and related technologies were awesome! There was some funny and cute banter with the casting director from Circ del Sole as she demonstrated using a cool disconnected WPF app. There was a fellow RD, Scott Stanfield, showing integration of SeaDragon into Silveright so we can look (in exquisite detail) at the memorabilia owned by the Hard Rock Cafe company, some thought-provoking demos of Silverlight on mobile devices and more.

Now to be honest, I've never been a fan of the web development model. Having done terminal-based programming for many years before coming to Windows, I find it hard to get excited about returning to that ancient programming model. Well, a worse one actually, because at least the mainframe/minicomputer world had decent state management...

AJAX helps, but the browser makes for a pretty lame programming platform. It is more comparable perhaps to an Apple II or a Commodore 64 than to a modern environment, and that's before you get into the inconsistencies across browsers and that whole mess. Yuck!

Which is why Silverlight is so darn cool! Silverlight 2.0 is really a way to do smart client development with a true web deployment model. Much of the power of .NET and WPF/XAML, with the transparent deployment and cross-platform capabilities of the browser world. THIS is impressive stuff. To me Silverlight represents the real future of the web.

It should come as no surprise then, that I spent my time in Silverlight 2.0 sessions after the keynote. Sure, I've been working (on and off) with Silverlight 1.1/2.0 for the past several months, but it was a lot of fun to see presentations by great speakers like Joe Stegman (a Microsoft PM) and various other people.

One of the best sessions was on game development with Silverlight. I dabble in game development whenever I have spare time (not nearly as much as I'd like), and so the talk was interesting from that perspective. But many of the concepts and techniques they used in their games are things designers and developers will likely use in many other types of application. Background loading of assemblies and content while the app is running, and some clever animation techniques using pure XAML-based concepts (as opposed to some other animation techniques I saw that use custom controls written in C#/VB - which isn't bad, but it was fun to see the pure-XAML approaches).

Many people have asked about "CSLA Light", my planned version of CSLA .NET for Silverlight. Now that we have a Beta 1 of Silverlight I'll be working on a public release of CSLA Light, based on CSLA .NET 3.5. Microsoft has put a lot more functionality into Silverlight 2.0 than they'd originally planned - things like data binding, reflection and other key concepts are directly supported. This means that the majority of CSLA can be ported (with some work) into Silverlight. The data portal is the one big sticking point, and I'm sure that'll be the topic of future blog posts.

My goal is to support the CSLA .NET 3.5 syntax for property declaration and other coding constructs such that with little or no change you can take a business class from full CSLA and have it work in CSLA Light. This goal excludes the DataPortal_XZY implementations - those will almost always be different, though if you plan ahead and use a DTO-based data access model even that code may be the same. Of course time will tell how closely I'll meet this goal - but given my work with pre-beta Silverlight 2.0 code I think it is pretty realistic.

Scott Guthrie indicated that Silverlight 2.0 Beta 1 has a non-commercial go-live license - right now. And that Beta 2 would be in Q2 (I'm guessing June) and would have a commercial go-live license, meaning it can be used for real work in any context.

The future of the web is Silverlight, and Beta 1 is the start of that future. 2008 is going to be a great year!

Sunday, March 09, 2008 5:18:27 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |