CSLA .NET for Silverlight is a version of CSLA .NET framework specifically written to support development of Silverlight applications. Microsoft's Silverlight is a cross-browser plug-in that uses XAML and a subset of .NET to enable rich client applications across platforms.

CSLA, written by Rockford Lhotka, has been around for over a decade. The purpose of CSLA is to provide developers with a solid framework to house business logic for applications. Microsoft .NET developers have adapted CSLA to new technologies as they emerge, and many developers use CSLA .NET heavily to construct robust, scalable .NET-based solutions supported on all Microsoft UI platforms, Windows, and the Web. CSLA .NET for Silverlight enables developers to create an object-oriented business layer that abstracts and encapsulates your business logic and data. CSLA .NET for Silverlight simplifies and standardizes the implementation of business logic, validation, and authorization within your objects. The goal is to provide an easy and consistent coding pattern by which you can encapsulate all your business logic within your object-oriented business layer. The result is a business layer that supports development of rich, interactive Silverlight applications.

CSLA .NET for Silverlight is a version of CSLA .NET framework specifically written to support development of Silverlight applications

CSLA .NET for Silverlight’s key features remain the same: full support for Silverlight data binding, N-level Undo, authorization / authentication features, validation rules, abstract data persistence, mobile objects that span physical boundaries to perform business functions, and multi-tier deployment model support.

Target Scenarios

You can use CSLA .NET for Silverlight to develop scalable line-of-business applications using Silverlight. Since Silverlight applications run in a Web browser, it is apparent that an application server component must be present in a Silverlight application. CSLA .NET for Silverlight has two primary ways to interact with an application server.

The most common one will probably be the CSLA .NET for Silverlight remote data portal. In this scenario, the Silverlight client calls the data portal for all CRUD operations, and the data portal will invoke CSLA .NET components on the server. In this case, CSLA .NET for Silverlight-based applications will still use CSLA .NET functionality to implement the data portal and business objects will move between the client and server just like they do in .NET.

The other primary scenario uses the CSLA .NET for Silverlight local data portal. In this case the Silverlight client calls the data portal, but the data access code runs on the Silverlight client. These data access methods will typically make calls to an external service (for example a WCF service, ADO.NET Data Services, or traditional Web service) to get or update data.

Stereotypes

CSLA .NET for Silverlight supports the following standard CSLA business object stereotypes:

  • Editable root.
  • Editable child.
  • Readonly root.
  • Readonly child.
  • Editable root list.
  • Editable child list.
  • Readonly root list.
  • Readonly child list.
  • Name/value list.
  • Command.
  • Dynamic root list.
  • Dynamic root.

Example

You will need a number of projects for a CSLA .NET for Silverlight solution. You can observe the solution structure in Figure 1. The first project is a .NET class library (Rolodex.Business.Server) that will also share business object class files with the Silverlight class library (Rolodex.Business.Client). You will also need an actual Silverlight application project (Rolodex) that compiles into the Silverlight XAP file/executable assembly. Finally, you need a Web project (Web) to host the Silverlight application. This project can, at the same time, host the CSLA .NET data portal application server components. Alternatively you can create a separate project to host the data portal (WcfHostWeb).

Figure 1: Solution structure for CSLA .NET for Silverlight-based application.
Figure 1: Solution structure for CSLA .NET for Silverlight-based application.

Business Objects in Detail

Business object stereotypes are at the heart of any CSLA application, whether Silverlight or .NET based. A key point of CSLA .NET for Silverlight is that all business objects are shared between the Silverlight client application and a .NET application (via the data portal). These are mobile objects and they travel across physical boundaries and runtimes. Any business object has sections that implement business functionality such as business logic, property declarations, validation and authorization rules, factory methods that call the data portal, and data access methods.

CSLA .NET for Silverlight simplifies and standardizes the implementation of business logic, validation, and authorization within your objects

Class Declaration

This is the standard way to declare a CSLA business object:

[Serializable]
public class Company : BusinessBase<Company>

You must inherit from a CSLA base class, thus getting the rich functionality available in CSLA. All of your objects need to be marked with the Serializable attribute to enable mobile object functionality.

Property Declaration

Here is what a typical CSLA .NET for Silverlight property declaration looks like:

private static PropertyInfo<string>
  CompanyNameProperty =     RegisterProperty<string>(
    new PropertyInfo<string>(
    "CompanyName",      
    "Company Name", 
    string.Empty));
  
public string CompanyName    
{
  get { return     GetProperty(CompanyNameProperty); }
  set     { SetProperty(CompanyNameProperty,      value); }
}

As you notice, CSLA .NET for Silverlight simplifies property declaration. The RegisterProperty pattern should be familiar to anyone who has done any custom control creation with WPF; it is similar to the way Dependency Properties work. Registered properties in CSLA .NET for Silverlight provide the ability to manage backing fields for you. There are numerous advantages to that, including transfer of data through the data portal. Despite its deceptively simple syntax, SetProperty() performs a number of functions for the developer, such as running business and validation rules, verifying access rights based on authorization rules, maintaining object states (such as marking the object “dirty” when the property changes), and raising the PropertyChanged event that data binding is listening to. All these capabilities are available out of the box.

Validation Rules

In order to supply validation rules, a developer must add them to the framework-supplied method:

protected override void     AddBusinessRules()    
{         
  ValidationRules.AddRule(
    Csla.Validation.CommonRules.    StringRequired, 
    new Csla.Validation.RuleArgs    (CompanyNameProperty)); 
  ValidationRules.AddRule(
    Csla.Validation.CommonRules.    StringMaxLength, 
    new Csla.Validation.CommonRules.    MaxLengthRuleArgs(
      CompanyNameProperty, 
      50)); 
}

CSLA .NET for Silverlight has the same built-in validation rules that CSLA .NET has, such as string required, maximum and minimum length for strings, minimum and maximum values for numeric fields, and more. In addition to that, developers can write and use an unlimited number of custom rules. The only requirement is to conform to a delegate declaration defined by CSLA: a function that returns a Boolean value.

Additionally, new to CSLA 3.6, is the notion of asynchronous validation rules. If you create a rule that needs to make a call to a remote server you will want to make your rule asynchronous due to the asynchronous nature of Silverlight service calls. There is an asynchronous validation rule delegate in addition to the standard validation rule delegate, otherwise the technique for creating asynchronous validation rules is the same.

Authorization Rules

In CSLA .NET for Silverlight authorization rules work in much the same way as standard CSLA. To declare authorization rules you simply specify what roles can perform which operations for a given business object:

protected override void     AddAuthorizationRules()
{
  string[] canWrite =     { "AdminUser", "RegularUser" };
  string[] canRead = { "AdminUser",     "RegularUser", "ReadOnlyUser" };
  string[] admin = { "AdminUser" };
  AuthorizationRules.AllowCreate    (typeof(Company), admin);
  AuthorizationRules.AllowDelete    (typeof(Company), admin);
  AuthorizationRules.AllowEdit    (typeof(Company), canWrite);
  AuthorizationRules.AllowGet    (typeof(Company), canRead);
  AuthorizationRules.AllowWrite    (CompanyNameProperty, canWrite);
  AuthorizationRules.AllowWrite    (CompanyIdProperty, canWrite);
  AuthorizationRules.AllowWrite    (DateAddedProperty, canWrite);
  AuthorizationRules.AllowRead    (CompanyNameProperty, canRead);
  AuthorizationRules.AllowRead    (CompanyIdProperty, canRead);
  AuthorizationRules.AllowRead    (DateAddedProperty, canRead);
}

Authorization is done against the current Principal set in ApplicationContext.User. To create a principal for CSLA .NET for Silverlight you must create a principal business object:

[Serializable]
public class RolodexPrincipal :     BusinessPrincipalBase
{ /* ... */ }

When a user logs in you simply fetch this principal like any other business object and set it to the current user on the ApplicationContext:

private static void SetPrincipal    (Csla.Security.CslaIdentity identity)
{
  RolodexPrincipal principal =     new RolodexPrincipal(identity);
  Csla.ApplicationContext.User = principal;
}

Factory Methods

The factory method is a standard pattern for a developer to expose object creation and fetching to the consumer. In CSLA .NET for Silverlight, since all data access is asynchronous, rather than the standard system of passing criteria as parameters and returning the resulting object, the recommended pattern for creating factory methods is with a Continuation Passing Style (CPS). With this technique you pass a delegate to a method that will be invoked when the asynchronous operation has been completed first, and then to your criteria parameters:

public static void GetCompany(
  int companyId, 
  EventHandler<DataPortalResult> handler)
{
  DataPortal<Company> dp =     new DataPortal<Company>();
  dp.FetchCompleted += handler;  
  dp.BeginFetch(new SingleCriteria<Company,     int>(companyId));
}

Data Access Methods

To get data into your business object you must implement the various applicable DataPortal_XYZ methods. If you are using the remote data portal, you will only need to implement these methods on the .NET server version of your business objects. To fetch a Customer object (for example), you will want to create a DataPortal_Fetch() method. You may override the base classes DataPortal_Fetch() method or create a method that exactly matches the criteria object you passed into your DataPortal call in the factory method. CSLA will call the appropriate overload:

protected void DataPortal_Fetch    (SingleCriteria<Company, int> criteria)
{
  using (SqlConnection connection =     new SqlConnection(
    DataConnection.ConnectionString))
  {
    connection.Open();
    /* Data Access Here */
    LoadProperty<int>(
      CompanyIdProperty,          reader.GetInt32("CompanyID"));
    LoadProperty<string>(
      CompanyNameProperty,          reader.GetString("CompanyName"));
    LoadProperty<SmartDate>(
      DateAddedProperty, 
         reader.GetSmartDate("DateAdded")); 
    /* Load Children Here */
  }
}

User Interface

CSLA has robust support to build rich user interfaces in Silverlight using CSLA’s data binding capabilities and custom Silverlight controls and classes.

CSLA .NET for Silverlight provides many features, such as data binding, authorization business, and validation rules, flexible data access, and N-level Undo

Data Binding

Data binding in Silverlight is almost syntactically identical to WPF. For example, if you are binding a text box to a company name, you can bind its text property to an underlying data source, while specifying the path to a target property (Listing 1). In this case, you are only specifying a path to the CompanyName property because the DataContext is set on the outer control (the Grid). You are also specifying the binding mode to be TwoWay in order to propagate changes made by the user to the underlying object.

CslaDataProvider

As you have probably noticed (Listing 1) you are binding all of your controls to the static resource, CompanyData. More specifically, you bind the grid to this resource, and all controls just specify the property name they are bound to. Here is what this resource’s definition looks like:

<csla:CslaDataProvider 
 x:Key="CompanyData"
 ManageObjectLifetime="True"
 IsInitialLoadEnabled="False"
 ObjectType="Company, Library ..."
 PropertyChanged=    "CslaDataProvider_PropertyChanged"
 FetchFactoryMethod="GetCompany"
 CreateFactoryMethod="CreateCompany"
 DataChanged=    "CslaDataProvider_DataChanged" />

CslaDataProvider is a CSLA .NET for Silverlight framework control that serves as a UI wrapper for business objects, enabling simplified syntax in XAML and greatly reducing the need for code-behind to perform functions on this business object. This control can automatically load the data into the object, although in the example IsInitialLoadEnabled is set to false. You can also specify the object you would like to use. You have to do this using an assembly qualified class name due to lack of support for x:Type markup extensions in Silverlight. You can also specify what method to call when filling the object with data (FetchFactoryMethod) or to create a new object (CreateFactoryMethod). In addition to that, you can subscribe to events that this object is raising. The DataProvider also knows how to save changes or cancel user changes via Save and Cancel methods. The DataProvider can work in conjunction with the InvokeMethod object to further reduce the need for code-behind. I’ll look at how this is done next.

InvokeMethod

InvokeMethod is a new class in CSLA .NET for Silverlight. Its purpose is to simulate commanding, which is missing in Silverlight. You can attach InvokeMethod to a control, have it listen to a specific control’s event, and invoke a specific method on another object in response to this event. Here is what the code looks like:

<Button 
 x:Name="SaveButton" 
 Content="Save"
 csla:InvokeMethod.MethodName=      "Save"
 csla:InvokeMethod.Resource=      "{StaticResource CompanyData}"  
 csla:InvokeMethod.TriggerEvent=      "Click"
 IsEnabled="{Binding Source=      {StaticResource CompanyData}, 
                     Path=CanSave, 
                     Mode=OneWay}" />

In this example, I’ve attached InvokeMethod to the Save button. As soon as the user clicks this button, the Save method will be invoked on CompanyData (the CslaDataProvider object). You can use InvokeMethod in other situations as well, invoking methods on arbitrary objects at run time. However, InvokeMethod integrates particularly well with CslaDataProvider, enabling / disabling controls based on the state of the data source. In the example above, SaveButton will only be enabled if the user made changes to the data. Additionally, IsEnabled property is bound to CslaDataProvider’s CanSave property. As a result, the button is only enabled when the object is valid and has pending changes.

Property Status

The PropertyStatus control allows you to display visual cues related to a particular property of your business object. Specifically it will display tool tips with messages for all broken validation rules, display a busy animation for any outstanding asynchronous operations, and disable or make read-only a control that is also bound to the same property. Simply declare this control in your XAML like this:

<      csla      :      PropertyStatus 
 RelativeTargetName="CompanyNameTextbox" 
 Property="CompanyName" 
 Source="{Binding Path=Data}" />

Object Status

This control’s purpose is to let a designer create storyboards based on a business object’s status. Some of the other controls, such as the MethodInvoke or the CslaDataSource, will give you ways to easily enable / disable controls through binding, but the ObjectStatus control allows you a broader range of interactivity by using the Visual State Manager. The authors will cover how this works in more detail in another article.

Conclusion

This article demonstrated how to use CSLA .NET for Silverlight to develop business applications for Silverlight. The primary goal is to allow developers to focus on their business problem, not the complex technologies behind the scenes. To this end, CSLA .NET for Silverlight provides many features, such as data binding, authorization business, and validation rules, flexible data access, and N-level Undo. These allow you to create robust, feature-rich Silverlight applications. CSLA also provides users the ability to encapsulate business logic inside business objects, allowing them to be reused in other .NET applications, such as Windows Forms, WPF, or ASP.NET with little or no code changes. The reverse is also true, as you can adapt your existing CSLA .NET-based application to be exposed in Silverlight with minimal code changes to your business objects. Please visit www.lhotka.net/cslalight for more information on CSLA .NET for Silverlight and CSLA .NET.

Listing 1: Data Binding example.

<Grid x:Name="LayoutRoot" DataContext="{StaticResource CompanyData}">
    <Grid.RowDefinitions>
      <RowDefinition Height="35"/>
      <RowDefinition Height="35"/>
      <RowDefinition Height="35"/>
      <RowDefinition Height="35"/>
      <RowDefinition Height="*"/>
      <RowDefinition Height="35"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="150"/>
      <ColumnDefinition Width="200"/>
      <ColumnDefinition Width="20"/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="Company Name:" TextAlignment="Right" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="0" Margin="6,6,6,6"/>
    <TextBox x:Name="CompanyNameTextbox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" Margin="6,6,6,6" Text="{Binding Path=Data.CompanyName, Mode=TwoWay}" IsReadOnly="True"/>
    <csla:PropertyStatus RelativeTargetName="CompanyNameTextbox" Property="CompanyName" Source="{Binding Path=Data}" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left"/>