Creating the foundations of your application
Before taking care of the smart client properly speaking, we must set up a data tier. The data tier is the place where the application will persist all of its data and is therefore commonly referred to as the persistence layer. On top of that layer, CodeFluent allows us to generate a middle tier which will contain a set of objects enabling developers to:
1. manipulate the data objects stored in the persistence layer,
2. define the business logic of our application.
Therefore, this middle tier is known as the Business Object Model (BOM). In the end, whatever the user interface or the type of architecture is, the persistence layer (containing the data) and the business layer (containing the business logic) are always the fundamental pillars of an application.
On top of those fundamental principles, in order to create a Silverlight smart client we need to create a set of services that will expose the BOM and allow our client to consume it remotely. This set of services corresponds to the services layer. The creation of those three layers won't be detailed in this article; instead this article extends the The Persistence, the Business, and the Silverlight Object Model one by using those generated layers in a Silverlight 3.0 client.
Preparing the development environment
At the very beginning of the The Persistence, the Business, and the Silverlight Object Model tutorial we created the Visual Studio projects corresponding to our Silverlight application: Sample.SilverApp (the actual Silverlight application) and Sample.SilverWeb (the web server hosting the Silverlight application).
In this previous tutorial we added all sources, resources and configuration files to the Silverlight application, however we still need to set-up the web server that will host our application. This web server must contain our Business Object Model which will allow us to manipulate data from the generated database. On top of that the web server must expose the WCF services to which the Silverlight application will connect to.
- Select the Sample.SilverWeb project,
- Click on the View All Files button of the Solution Explorer,
- Include all .svc files to the project,

Note: Svc files are used to host WCF services in a IIS web server. Those files were generated using the server templates in the "The Persistence, the Business, and the Silverlight Object Model" tutorial. - Include the ClientAccessPolicy.xml file to the project.
![]() |
Note: To enable a Silverlight control to access a web service in another domain, the service must explicitly allow cross-domain access. Silverlight supports two different mechanisms for services to opt-in to cross-domain access: by placing a clientaccesspolicy.xml file or a crossdomain.xml file at the root of the domain. For more information, please check the msdn: http://msdn.microsoft.com/en-us/library/cc197955(VS.95).aspx Note: This file was generated using the server templates in the "The Persistence, the Business, and the Silverlight Object Model" tutorial. |
Furthermore, we now need to add the needed references to consume the WCF services exposed. To do so:
- Select the Sample.SilverWeb project,
- Right-click on the project node, select Add New Reference...,
- In the new dialog, select the Projects tab and select the Sample project.
At this point your Sample.SilverWeb project should look like this:
The Sample assembly contains the BOM and services which will allow our Silverlight application to manipulate the data stored in the generated SQL Server database. The Web.Config that was generated from the server templates configures the WCF services and the svc files allow them to be used in an IIS server. Our client access policy is defined in the ClientAccessPolicy.xml file: we're now ready to develop our Silverlight application.
Developing the UI
The UI layer should only contain presentation code, all of the business logic should be in the Business Object Model (BOM). Hence, BOM objects are made to be data bound to, and provide advanced features to ease presentation layer developments such as validation capabilities, paging, sorting, caching, and so on. The Silverlight Object Model (SLOM) that we generated in the Sample.SilverApp assembly is a remote version of the BOM containing the same capabilities (data binding, data validation, etc.) and taking care of all communication and transport matters. Moreover, the default Silverlight development model is asynchronous: all calls to web services must be asynchronous. Even though it's a necessity, it proves to be a real drag when developing a real business application.
Therefore, The SLOM wraps all service calls and takes care of the asynchronous call management on top of the communication management. It's completely transparent for the developer, and consequently, the developer can develop apparently synchronous code whilst actually being compliant to Silverlight's asynchronous development model. This results in a dramatically improved development experience and greatly simplifies the produced source code. In the end developers can truly focus on the added-value of their application.
In this tutorial, we'll focus on a basic example that illustrates the data binding principle. We're going to create a Silverlight application which allows end-users to create and list customers. You'll see that thanks to the SLOM, practically no code behind is needed, and all communication matters are handled for us. Hence, the presentation layer will contain exclusively presentation code: this is a capital concern in order to create highly evolutive and maintainable applications. Thanks to this architecture, adding user interfaces is made easier, since only the "look & feel" is changed, we're not touching to any business logic in the presentation.
In the MainPage file of the Sample.SilverApp project, we'll create our user interface. Here's the XAML:
| MainPage.xaml | Copy Code |
|---|---|
|
<UserControl x:Class="Sample.SilverApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="300"> <UserControl.Resources> <DataTemplate x:Key="CustomerDataTemplate"> <StackPanel> <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/> <TextBlock Text="{Binding Path=Address}" Margin="5,0,0,0"/> </StackPanel> </DataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot"> <StackPanel> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0"> <TextBlock Text="Name:"/> <TextBox Name="_customerNameTextBox" Margin="2,0,2,0"/> </StackPanel> <StackPanel Grid.Column="1"> <TextBlock Text="Address:"/> <TextBox Name="_customerAddressTextBox" Margin="2,0,2,0"/> </StackPanel> <Button Grid.Column="2" Name="_createCustomerButton" Content="Create" VerticalAlignment="Bottom" Click="OnCreateCustomerButtonClick"/> </Grid> <Button Name="_loadCustomerListButton" Content="Load Customer List" Margin="5,5,5,5" Click="OnLoadCustomerListButtonClick"/> <ListBox Name="_customerListBox" MinWidth="450" MinHeight="100" ItemTemplate="{StaticResource CustomerDataTemplate}"/> </StackPanel> </Grid> </UserControl> | |
Here's the code behind:
| MainPage.xaml.cs | Copy Code |
|---|---|
|
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void OnCreateCustomerButtonClick(object sender, RoutedEventArgs e) { Customer customer = new Customer(); customer.Name = _customerNameTextBox.Text; customer.Address = _customerAddressTextBox.Text; ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { customer.Save(); })); } private void OnLoadCustomerListButtonClick(object sender, RoutedEventArgs e) { ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { CustomerCollection customers = CustomerCollection.LoadAll(); Dispatcher.BeginInvoke((UpdateCustomerListDelegate)UpdateCustomerList, _customerListBox, customers); })); } private delegate void UpdateCustomerListDelegate(ListBox listBox, CustomerCollection customers); private void UpdateCustomerList(ListBox listBox, CustomerCollection customers) { listBox.ItemsSource = customers; } } | |
![]() |
Note: Web service calls cannot be made on the UI thread, and non-UI threads cannot update the UI; this is the reason why we're using threads from the ThreadPool to load or save our data, and the Dispatcher through a delegate to update the UI. |
Pressing F5 should launch your default web browser on the defined start page which should contain your Silverlight client. Once the Silverlight client was loaded by the browser, create several users and then list them.
Here's what you should get:
Troubleshooting Errors
The default template for the App.xaml.cs file catches exceptions, and prints only the message to the user, losing the stack trace and the initial exception. For development purposes, it's way more convenient to modify the source code in order to display the initial exception. Here is a modified version of the standard ReportErrorToDOM method that was used to create the sample:
| App.xaml.cs | Copy Code |
|---|---|
|
private void HandleException(Exception e) { string errorMsg = e.ToString(); errorMsg = errorMsg.Replace('"', '\'').Replace(Environment.NewLine, @"\n"); System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application: " + errorMsg + "\");"); } private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) { try { Exception ex = e.ExceptionObject; while (ex is TargetInvocationException) { ex = ex.InnerException; } HandleException(ex); } catch (Exception) { } } | |
