Introduction
Started as Windows Forms analist/developer years ago, and given the shifting trend towards Web Application development, I am looking for a new challenge in the wonderful world of application development. After a moment to have stood in ASP.NET and ASP.NET MVC framework, I finally made the decision for me to concentrate on developing Silverlight LOB applications.
This article will introduce the intermediate and advanced Silverlight developer to Silverlight concepts like RIA-Services, DTO's (Data Transfer Objects), creating DataTemplates, ValueConverters and using the DomainDataSource.
Background
This article doesn't target the creation of fully fledged SilverLight LOB applications, including MVVM pattern, BusinessRule Validation, Styling and so on, but will concentrate on transferring DTO's as lightweight objects for showing a simple demo read-only bike webshop list. DTO's, or Data Transfert Objects are so called "leightweight" POCO (Plain Old CLR Objects), which contain the minimum of information (properties) to transfer data from the ServerSide DomainService to the client. In our demo case, the DTO objects will be filled by bike info and will be the ItemsSource for a bound ListBox.
Explaining the application creation steps.
The person reading this article should already have a reasonable understanding how Silverlight LOB applications are build, as I won't explain those details. If you are not familiar with those concepts, please refer to the main Silverlight site first, which you can find by activating next URL :
Server Side
I will build the application gradually starting by explaining the underlying database, creation of the Entity Framework model, creation of the DTO which will contain the bicycle information and creation of domain service for loading the bike information in a DTO list. These elements are part of the WebSite Project included in the project:
The demo database is included in the project under the /App_Data folder and is called MountainBikeDB.mdf(attached DB file). The database countains a main table, named bike which contains the main bike properties, other related tables contain data which are applicable on each type of bike, like frametype, forktype, braketype, type of bike and so on, the relational structure looks like:
The DomainService which will be explained in a moment, holds a reference to an EntityFrameWork context which is derived from our attached SQL-Server Database:
The purpose of our application is to show a bike summarylist holding bike information. For this purpose, a read-only set of objects will satisfy. So as we don't need editable objects (we are only exposing the R from CRUD acronym, C= Create, R= Read, U= Update, D= Delete) we prefer a lightweight object to transfer our data to the client. This lightweight object will be stored in the /Models folder of our WebProject, it's a simple class withe some anotations for the DomainService (like the [key] attribute, to identify uniquely each object in the list.
namespace SilverlightLOB_RIA_DTO.Web.Models
{
public partial class BikeDTO
{
[Key]
[Editable(false)]
public int BikeID { get; set; }
public string BikeName { get; set; }
public byte[] BikeImage { get; set; }
public decimal ModelNumber { get; set; }
public string FrameType { get; set; }
public string BikeType { get; set; }
public string ForkType { get; set; }
public string BrakeType { get; set; }
public string GroupSet { get; set; }
public string WheelSet { get; set; }
public int? InStock { get; set; }
}
}
Note that the BikeID
property is annotated with the [Key]
and [Editable(false)
] attributes. The reason for this is that the user shouldn't be allowed to update that field, because it is a serverside generated auto-incremental key. A second reason for the [Key] annotation is the fact that it is required by the RIA-DomainService, as each object should be uniquely identifiable.
Finally, since we will only expose a read-only list of bikes in our SilverLight client application, we could annotate each property with the [Editable(false]
annotation, but, in case we want to re-use this DTO to do alse some updates in another view, we didn't do that.
Next our DomainService
which resides in the /Services folder of our WebProject, exposes 1 method, which reads bike information from our Entity Framework Context and creates a DTO object for each of them. Finaly, a list of those objects are returned to the client part of our application (the Silverlight application). The Service is a so called Domain Service Class service, which implementation is shown as next:
[EnableClientAccess()]
public class BikeService : LinqToEntitiesDomainService<MountainBikeDBEntities>
{
public IQueryable<BikeDTO> GetBikeDTOList()
{
return from bike in this.ObjectContext.Bikes
orderby bike.BikeName
select new BikeDTO
{
BikeID = bike.BikeID,
BikeName = bike.BikeName,
BikeImage = bike.Photo,
ModelNumber = bike.ModelNumber,
FrameType = bike.FrameType.FrameTypeName,
BikeType = bike.BikeType.BikeTypeName,
ForkType = bike.ForkType.ForkTypeName,
BrakeType = bike.BrakeType.BrakeTypeName,
GroupSet = bike.GroupSet.GroupSetName,
WheelSet = bike.WheelSet.WheelSetName,
InStock = bike.InStock
};
}
}
Voila ! that's wat our server side is about, let's move on to explain the Client Side part now !
Client Side General Concepts
A first word ...
Without going in details concerning the concepts of the Silverlight LOB application template, you may have noticed that our solution ghosts 2 projects, namely the WebPart (SilverlightLOB_RIA_DTO.Web) and the ClientPart (SilverlightLOB_RIA_DTO). The Web part contains a compiled version of the client part (Silverlight) in means of a .xap file. On the other hand, the client part holds references to the DLL's concerning the DomainServices (System.ServiceModel.DomainServices.*) .
The combination of those references makes communication between the two layers possible. Also notice (if you put "show all files") on, that you can, on the client site, browse to a hidden folder called Generated Code, which, among others, includes the definition of our DTO data transfert object .
When you add properties to our DTO-object on the server-side part, or validation rules by means of metadata classes, and you re-compile the solution, then the Generated_Code section on the client will also reflect those changes. Once more, the goal of this article isn't to explain the ins and outs of the Silverlight LOB-template, but it is important to know that your model on the client reflects the model created on the server !
The .xap file on the WebSite contains the complete SilverLight Application (in zipped form). When the application is deployed to a WebServer, then, at first client request, the .xap file will be sent to the client and unzipped. The WebSite also checks, before deploying the client part, if the SilverLight Runtime is already installed, if not, the user will be noticed that the SilverLight runtime will be installed first.
Ok, enough theory, let's look now how the client gets and displays the Data in the bike's ListBox !
Client Infrastructure Concepts
I've been around with .NET for a while now, started in 2003 with C# Visual Studio Standard 2003. Nowadays, we are overwhelmd with information concerning infrastructure patterns, creating applications in n-tiers (layers) is the way to go, monolithic programming is equal to bad design nowadays. When I started .NET, there wasn't much like separating your presentation layer from the business and the data-access layer. Most step-by-step tutorials on MSDN showed us the RAD (Rapid Application Development), our should I say Q and D (Quick and Dirty) approach, dragging and dropping DataSources on windows forms, wich generated TableAdapters, BindingSources , BindingNavigators and so on (at least in VS2005 with the typed dataset introduction). At first this was ! wow, look guys, no code ! ... but everything was pushed in the presentation layer, which lead to poor application maintenance. To show this concept, I've added a little demo application to the solution, called BikeAdmin, you can investigate some time to it to so how monolothic application design looks like. In fact the TableAdapterManager, should be wiped from the User interface and be put in it's own class, namely a DataService class. Next we Also should include a BusinessClass for our Bike, this class requests data from the DataService, add's businessrules (with typed DataSets you can use the Column_Changing/Changed, Row_Changing/Changed ... eventhandlers to "hook" your business logic into. But, Unlike the SilverLight Business Template, you had to create your framework yourself. Before hitting the SilverLight client implementation, let's have a quick look how this n-tier seperation could be achieved in the "old-windows-forms-days" ! I have added a Windows forms project to show this, it's called BikeAdmin.
The Monolithic approach, Drag and Drop of the DataSource
If, within the BikeAdmin project, the FormBike represents the "form contains everything" approach. Just by dropping the DataSource for the Bike DataSet, a bunch of code was generated to capture the data, hook in the databindings and loading/saving the data. Unfortunately, everything was put in the "Code Behind" file, I you look at the code in this form, you will see that TableAdapters are created within the form's code behind file and all data related issues are handled here. This way, you get your form quickly up and running, but it lacks code-reuse, separation of concerns, code maintianability and unit-testing.
Layered development methodology (n-tier)
A second approach, as demonstrated in the FormGetBikeList puts the TableAdapters in a DataServices class which exposes public methods to the BusinessClass, the BusinessClass
can be extended with businessrules and servers as a gateway between the DataAcessLayer and the PresentationLayer. Please refert to the code for further details.
Client Side SilverLight Application
Prototyping
As our data will be presented in a ListBox with quit a complex structure, it's a good thing to prototype the "ListItem" appereance in a separate page (our by using Expression Blend, which is a great designer tool, but not in scope of this article).
So when you bind a "bunch" of objects to a ListBox, the ListBox isn't aware where to bind to, and will bind to the ObjectStructure itself (if no override for the ToString()
method was implemented). Each item in our ListBox should represent bike information. The ListBox exposes an ItemTemplate
, and within the Itemtemplate you can define a DataTemplate, this DataTemplate can then be stored as StaticResource
(within the containing page or in a multi-purpose dictionary) and can be applied to our ListBox. I first designed this DataTemplate in a separate folder called /ProtoType, and loaded it with static data. The result is shown beneath:
I won't go in the details of the XAML-code, but feel free to take some time how the template is build up. Most important is, once the form holding or list is created, i will copy/paste the template from the prototype and add it as Static Resource of the page. Finaly i will replace the static data with the Binding elements of the DataContext, as exposed by the DomainDataSource.
The DomainDataSource
In SilverLight, you have a lot of ways to get the data from the server and bind it to the client. In this demo, we will be demonstrating The DomainDataSource approach, which you can compare with the DataSource Drag/Drop facilities in the former Windows Forms technology. Yes, we will go the Quick and Dirty way this time, but that's all right for our purpose, namely, exposing a read-only ListBox containing bike information. Pleae note when you want to develop real professional and easy maintainable SilverLight LOB applications, including CRUD operations, then you should avoid the XAML-bound DomainDataSource approach and implement the MVVM (Model-View-ViewModel) pattern, which encourages separation of concerns, code reusability and unit testing. Although there are many ways how to implement MVVM-pattern in SilverLight, with many different opinions and helper frameworks, but for now, we skip this part and concentrate on binding data directly in the XAML-page using the DomainDataSource approach!
In our case, i have created a new SilverLight Page in the /Views folder, named BikeListView.xaml. This page will contain our bikelist, so we have to "drag" our DataSource on to the canvas of the page. First (with the xaml page opened) open the DataSource toolbox:
Next toolbox will appear on the left side of the screen:
Finaly drag the BikeDTO DataSource on the Surface of the current xaml page (the one which will contain our ListBox.
Next RIA-Service related references will be added on top of the page:
These are equal as adding serviced WCF-references to a client application.
The drag/drop action will also have result in adding the DomainDataSource Proxy into the XAML code, in our case the one which will load our bike data into our ListBox:
The code surrounded with the red box are manualy added filtering and sorting options, because we want the list by default be sorted on bikename and be filtered on biketype (cross country / dirt / downhill / freeride) are valuable options to filter on.
Let's investigate some time to explain the different aspects of the generated XAML-code:
- The AutoLoad property is set to True, meaning that the call to the server will be made as soon as the view is loaded.
- An event handler is assigned to handle the LoadedData event. This handler will load our bike DTO objects.
- The QueryName property is set to the name of the query domain operation that you want to call on the domainservice.
- The DomainContext property is assigned an instance of the domain context that will handle obtaining the entity collection from the server.
The SearchTextBox
The search Textbox, which is on top of the page makes filtering by biketype possible. The ElementName of the TextBox is bound to the PropertyPath of the "BikeType" property of our DTO
and the Operator defaults to search for biketypes with the 'StartsWith' clause.
The ListBox and DataPager
Our ListBox contains ListBoxItems, with an ItemTemplate equals to the StaticResource pointing to _bikeItemTemplate (see full XAML code for more info).
The ItemsSource of our ListBox points to the DataLoader method of our DomainService, the Path indicates the Data, in our case a list of bike DTO objects as returned from the server.
Although we let our DomainService load 100 DTO's by single call, we create a DataPager to navigate between them in a paired way.
It also has an IsTotalItemCountFixed
property that if set to true will stop the user from navigating beyond the calculated number of pages (by disabling the Next button).
If you inspect the XAML Code, you will also notice a "IsBusyIndicator
", which will display a progress bar while data is loading from the server.
A Final Word
Well, I hope you have been enjoying this article about SilverLight LOB technology, just run the project to see the home page show up (on the photo, me myself and I with my youngest son, click on the BikeListView button to load the bikelistbox ...). There is a lot more to do then the contents exposed in this article. Silverlight 4 LOB template is realy ready for building consistent line of business applications, including validation, transaction, implementing the MVVM-pattern to make team related projects more accessible. To me Silverlight has a great future and more and more people are adapting it not only as a replacement or alternative for Adobe-Flash, but also it gives us a good symbiose between ASP.NET and Windows Desktop Development. In the beginning, it's quit a steap learning curve to understand alle the new technology within SilverLight LOB, but ones you're in it, i'm sure you will never look back to your old platform (ASP.NET or WinForms). For myself, I will continue in investigating my knowledge in SilverLight LOB and hopefully professionaly make the switch to this platform as soon as possible!