Introduction
Real business applications are completely different from samples that can be found in the Internet. The real applications have many layers because all architects are going to divide an application into them to decrease complexity and improve readability of the source code.
Any Silverlight application is a client application. It means the compiled code of such an application runs on the client tier and it has to have access to data that hosted on the server (middle) tier.
There are many ways to get data from the client tier:
- Web Services (Asp.Net web services, Wcf etc)
- Ado.Net Data Services
- .Net Remoting
- .Net Ria Services
Last one was developed specially for rich internet applications (Ria) and provides methods and framework to link client and middle tiers.
.Net Ria Services library adds new kind of Visual Studio project templates "Ria Services Class Library" which allows to create N-tier class libraries.
Also, .Net Ria Services has build-in abilities to use secure connection to protect important data like logins, passwords etc.
Building an application on the Ria Services basis has some tricks, that are not described, because mentioned technology is pretty new and it is available as Preview version (Jul 2009). So, I am going to unlock secrets of building real business applications based on .Net Ria services and Ria services Class Library.
Background
In my opinion, any silverlight business application must have following features:
- Separate tiers (middle, client) and data transfer between them;
- Access to data tier (database);
- Authentication;
- Data transfer between tiers via secure connection.
.Net Ria Services and .Net Ria Services Class Library allow to implement all features above. Demo application has all mentioned features and can be use as a skeleton for all other silverlight business applications.
Technical requirements
Following software was used:
- Windows XP SP3/IIS 5.1
- VS 2008 SP1
- .Net 3.5 SP1
- Microsoft Silverlight Projects 2008 Version 9.0.30730.126
- Silverlight 3.0.40818.0
- Silverlight Toolkit July 2009
- Silverlight 3 Developer Package
- Silverlight 3 SDK
- .NET RIA Services (Jul 2009 Preview)
- SelfSSL tool from IIS Resource Kit
- MS SQL Server 2005
- Web Development Helper 0.8.5.1 (IE plug-in)
Getting started
This article is concentrated on the back-end rather than the front-end part of the Silverlight applications. So, we can start developing the application based on Business Application project template. This template contains several predefined views, Login and passwords controls. Also, this template contains a couple of services (Authentication, Registration) that can be called from the client tier via Ria services mechanism.
Note: Business Application project template is available if you have installed .Net Ria Services framework (see below for details).
Changes in the solution structure
Eventually, "Business Application project" template provides some source code that can be used in the real business application. But it is not enough for real application.
First of all, I have to add a new type of the project to the solution - .NET RIA Services Class Library. This approach allows to build the bridge between client tier (silverlight application) and middle tier.
After that, I have to move Services from web application to RIA Services Class Library. The services will be available for client tier as they are available now.
Then I have to add an entity data model (model of the database) to get access to data. An Authentication and a traffic encryption between the client tier and the middle tier will be supported also.
As a result, my application should consist of four projects:
BASample.Web
. This project is a web application and it hosts silverlight application. BASample.Data
. This project implements access to the data tier and contains all services that are used by silverlight application. BASample.Silverlight
. This project contains all controls and windows that will be displayed for a user. BASample.Data.Silverlight
. This project allows to get access to middle tier to the silverlight application.
Changes in the created solution.
Usually, I change root namespace, assembly name, name of project for each created project (via Project properties window). I'm going to use BASample.Silverlight
as a namespace, name of project and name of assembly.
To change namespaces of the Silverlight application, I should change namespaces both in *.cs files ('namespace' and 'using' areas) and in *.xaml files. Attributes of root element of *.xaml file contain namespaces to change:
x:Class="<Namespace>.<className>"
xmlns:app="clr-namespace:<Namespace>"
Sample of the root element of *.xaml file (The namespace to change is highlighted and underlined):
<controls:ChildWindow
x:Class="BusinessApplication1.LoginWindow"
x:Name="childWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:dataform="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
xmlns:activity="clr-namespace:System.Windows.Controls;assembly=ActivityControl"
xmlns:app="clr-namespace:BusinessApplication1.Silverlight"
Width="400"
Title="Login"
Style="{StaticResource LogRegWindowStyle}">
I change the namespace of services and other *.cs files (I use BASample.Web
) for web application.
I should update .Net Ria services link in the Silverlight application after renaming web project.
Fig. 1. How to update Ria services link after renaming web application.
Also, after updating Ria services link I delete auto-generated file BusinessApplication1.Web.g.cs
from Silverlight project (Generated_Code
folder) and rebuild the solution - auto-generated file will be recreated with the different name BASample.Web.g.cs
. Successful build means that all changes were done correctly.
Adding .NET RIA Services Class Library to the solution.
I've installed Ria Services framework (you can find it here) and I see two additional project templates in the list of Silverlight templates.
Fig. 2. List of Ria Services Silverlight project templates.
I select '.NET RIA Services Class Library', enter name for the project BASample.Data
and click 'Ok' to add it to the solution. It will create a solution folder BASample.Data
and add two additional projects into there.
Then I update names of assemblies, root namespaces and names of projects for middle and client tiers of RIA Services Class Library (see fig. 3, 4 for details)
Fig. 3. Properties of the middle tier of added .NET RIA Services Class Library.
Fig. 4. Properties of the client tier of added .NET RIA Services Class Library.
I specify correct .Net Ria Services link for client tier library. A correct value is the name of the middle tier of the RIA Services Class Library (BASample.Data
) because it will contain data entity model.
After these changes the solution can be built successfully.
Next step is adding the data entity model to the solution. According to my structure of projects, I should add it to the BASample.Data
project, the Model
folder (Select Folder - Add New Item - ADO.NET Entity Data Model).
I select existing database, uncheck 'Save entity connection settings in App.config' (I will explain why a bit later) and copy connection string into buffer. On the next page I select all required tables (In my sample there is only one table, which will be used for authentication), enter a namespace for model BASample.Data.Model
and click Finish
.
Note: Only tables with primary key will be added to the model.
After adding model into the middle tier, I'm going to update .Net Ria Services link in the BASample.Data.Silverlight
application (it should be set to BASample.Data
).
Extracting Ria context class.
Before moving services from web library, I should extract Ria context class from auto-generated class into separate one because an instance of Ria context must be only one for the whole silverlight application and shouldn't be placed anywhere except BASample.Silverlight
project (similar to HttpContext for web applications).
I just add a new class RiaContext
into BASample.Silverlight
and put there source code for that class.
Moving services from web library to separate one
After successful adding .NET RIA Services Class Library to the solution I'm going to move service functions from web application into BASample.Data
.
First of all, I add a folder DomainService
into BASample.Data
. This folder will contain all service classes that will work with data model directly. Then I add all required services into that folder (Select Folder 'Domain Service' - Right mouse button click - Add New Item - Domain Service Class) one by one. For example, table AppUser
is mapped to AppUserService
service class (I want to have separate class for each entity).
Fig. 5. This dialog allows to set properties for adding domain service classes.
Added class will be used instead of UserRegistrationService
(see BASample.Web
project).
Next step is adding Authentication service (Select Folder 'Domain Service' - Right mouse button click - Add New Item - Authentication Domain Service).
Fig. 6. This dialog allows to add new Authentication domain service class.
After step above, I go to the main Silverlight project BASample.Silverlight
and add a reference to the BASample.Data.Silverlight
project because it contains auto-generated class based on services of BASample.Data
.
Then I start replacing invocations of old service functions with new ones. After that, I remove a .Net Ria Services link to BASample.Web
from BASample.Silverlight
and all service classes in BASample.Web
can be excluded from the project. Also, auto-generated class can be deleted from BASample.Silverlight
project.
Known issues
First one appeared after moving Authentication service from BASample.Silverlight
project. So, I had to initialize authentication context of the silverlight application manually. There are two ways to do it: via app.xaml and via app.xaml.cs:
Sample of app.xaml
file. Authentication context initialization is highlighted.
<Application.ApplicationLifetimeObjects>
<app:RiaContext>
<app:RiaContext.Authentication>
<appsvc:FormsAuthentication DomainContextType="Pausoft.AuthSample.Data.DomainService.AuthenticationContext, Pausoft.AuthSample.Data.Client, Version= 1.0.0.0"/>
</app:RiaContext.Authentication>
</app:RiaContext>
</Application.ApplicationLifetimeObjects>
Sample of app.xaml.cs
file. Authentication context initialization is highlighted.
private void Application_Startup(object sender, StartupEventArgs e)
{
this.Resources.Add("RiaContext", RiaContext.Current);
((DomainAuthentication)RiaContext.Current.Authentication).DomainContext = new AuthenticationContext();
this.RootVisual = new MainPage();
}
Second issue was related to database and connection string. 'Add new data entity model' dialog allowed to store connection string into .config
file and I warned about it and proposed to copy connection string into the buffer. The root of that issue is the connection string needs to be available at the runtime of the web application. It means the connection string in app.config
file of BASample.Data.Silverlight
will not be read by the web application and it will raise an exception "The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.".
This issue can be resolved by moving (adding) connection string to web.config
file of BASample.Web
project.
Sample of web.config
file. Connection string is highlighted.
<connectionStrings>
<add name="AuthSampleEntities" connectionString="Past_Connection_String_Form_Clipboard_Here" providerName="System.Data.EntityClient" />
</connectionStrings>
Some other issues you can find during the work on silverlight business applications:
Custom authentication for Ria applications.
To implement custom authentication, I should override some virtual methods in AuthenticationService
class. First of all, I should override methods for initialization and destroying and add a reference to AppUserService (I will use it for checking username/password).
private AppUserService appUserService = new AppUserService();
public override void Initialize(DomainServiceContext context)
{
appUserService.Initialize(context);
base.Initialize(context);
}
protected override void Dispose(bool disposing)
{
if (disposing)
this.appUserService.Dispose();
base.Dispose(disposing);
}
Then I should override methods that implement user's validation.
protected override bool ValidateUser(string userName, string password)
{
return appUserService.IsValidAppUserNamePassword(userName, password);
}
protected override UserIdentity GetAuthenticatedUser(IPrincipal principal)
{
UserIdentity user = CreateUser();
if (this.appUserService.DoesAppUserExist(principal.Identity.Name))
{
AppUser appUser = appUserService.LoadAppUserByName(principal.Identity.Name);
user.Name = appUser.Name;
user.AuthenticationType = principal.Identity.AuthenticationType;
}
return user;
}
So, these changes allow to easily implement custom authentication for any business application.
Using Https protocol for Ria Services operations
Ria services are based on Rest protocol, so it does not encrypt data transfer between the client tier and the middle tier.
Nevertheless, Ria services has got some built-in options to support secure connection. For example, the EnableClientAccess
attribute of each service class has argument RequiresSsl
. That boolean attribute means whether a class can only be accessed using https. This feature is very important for services that work with secure data (e.g. authentication service, financial data etc.).
Note: Visual Studio built-in web server (Cassini) does not support https protocol. So, IIS should be used instead.
Sample of using EnableClientAccess
to secure all operations of AuthenticationService
class.
[EnableClientAccess(RequiresSsl = true)]
public class AuthenticationService : AuthenticationBase<UserIdentity>
{
...
}
Note: If I use https for the silverlight's hosting application (BASample.Web
), the same protocol will be used for the communication between the silverlight's client and the middle tier no matter what argument was used for the EnableClientAccess
attribute.
Known issues:
- Integrated Windows Authentication option should be enabled for application's virtual folder (Select virtual folder in IIS - Right mouse button click- Properties - Directory security tab - Edit anonymous access and authentication control - Check Integrated Windows Authentication option);
- IE6 and IE7 (don't know anything about IE8) raise an exception when the url is based on the secure protocol (see here for details). Other browsers are working well.
Adding secure certificate to IIS
To use advantages of a secure connection, I should install a secure certificate into IIS.
The easiest tool to create and deploy the secure certificate is SelfSSL (you can find it in the Internet Information Services (IIS) 6.0 Resource Kit Tools). This tool works well with IIS 5.1 also.
I use following command line to install self-signed certificate:
selfssl.exe /T /V:730 /S:1
- /T - Adds the self-signed certificate to 'Trusted Certificates' list.
- /V:730 - Specifies the validity of the certificate (in days).
- /S:1 - Specifies the id of the site. Id of the web site is displayed in IIS console - column
Identifier
in the list of web sites. - /N:CN=domainname - Specifies the common name of the certificate. By default it uses computer name. It's ok for me and I didn't specify it in the command line.
Cross-domain scenario
As mentioned above, AuthenticationService
will use https
connection only. But the silverlight application is loaded by http protocol. That means the application calls a service from another domain (two applications that use http and https protocols are in different domains though they are hosted in the same virtual folder) and it is a cross-domain scenario.
By default, the cross-domain scenario is not allowed and the application will not work. To avoid that issue, I'm going to create clientaccesspolicy.xml
. That file contains instructions about what external services can get access to the services.
Sample of clientaccesspolicy.xml
file.
="1.0"="utf-8"
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
The example above allows to get access from any external domain.
I put this file in the root of the web site (not the root of my application!). When silverlight application tries to get access to the services via secure channel, this file will be read and it will allow the service to work with a request from the silverlight application.
Note: If I use https for the silverlight's hosting application (BASample.Web
), the file clientaccesspolicy.xml
will not be loaded because the client tier and the middle tier are working in the same domain.
Note: If If you are planning to allow to non-silverlight clients to get access to you services, you have to use crossdomain.xml
file also. See description of that file here.
Demo application
Source code of the application contains all described above techniques and ready to be compiled and deployed. There are some things developer should change before running:
- Create virtual folder for the web application;
- Deploy the database (See DB folder for the database sample) and update connection string in the
web.config
; - Create and deploy secure certificate by SelfSsl tool;
This application allows to open login dialog, enter correct credentials and be authenticated based on credentials in the database. After that, a user can logout. Also, the application allows to add new member in the database and use added credentials for logging in.
Fig. 7. The application was accessed via http
protocol but Authentication service was accessed via https
.
Fig. 8. The application was accessed via http
protocol but user was successfully authenticated via https
protocol.
Fig. 9. User registration dialog.
Fig. 10. User's registration information was successfully added to the database (via http
protocol) and user was successfully authenticated via https
protocol.
Known issue:
- If any changes in silverlight application were made, just rebuilding is not enough. The application should be relaunched in the new browser's window; otherwise, changes weren't applied.
Wrapping up
This article is oriented on developers and architects, who work on business applications. It describes:
- how the silverlight solution can be divided into separate layers using .NET RIA Services Class Library;
- how the access to the data layer (database) can be established;
- how the custom authentication can be implemented;
- how to establish and use an https connection for the silverlight application.
History
- Version 1.0 (2009-11-07) - Initial release.
Max currently is a senior developer at software company.
He lives with his wife Tatiana and son Zakhar (4 yrs) in Minsk, Belarus, but they dream to live in New Zealand.