Intersoft ClientUI 8 > ClientUI Fundamentals > Application Framework Overview |
ClientUI Application Framework is a powerful application management framework that enables composite application development for the Silverlight and WPF platform.
This overview describes the anatomy of a ClientUI application, the fundamental concepts and features of the application framework, as well as providing guidance to partition your applications to achieve modular design for better scalability and extensibility.
This section contains the following topics:
A ClientUI application is abstracted into several classes implemented in ClientUI framework to facilitate a generic object model that can be used consistently in a Silverlight and WPF project. At the heart of ClientUI Application Framework is the ApplicationPackage class, which is analogous to a ClientUI application. Because an ApplicationPackage class represents a ClientUI application, many of the services and features for a ClientUI application can be accessed and manipulated through the ApplicationPackage class.
ApplicationPackage class derives from BasePackage class which contains numerous settings used to define a package. The ApplicationPackage class has relations to a number of classes, such as DependencyPackage, DependencyAssembly and ExternalResouce, which forms the core application model for a ClientUI application.
The following illustration describes the class models that represents a ClientUI application, which comprises of ApplicationPackage, DependencyPackage, DependencyAssembly and ExternalResouce.
As seen in the above class diagram, both ApplicationPackage and DependencyPackage share numerous properties in common, which are defined in the BasePackage class. DependencyPackage represents one or more assemblies that can be referenced and shared to an ApplicationPackage. The DependencyAssembly defines the metadata that represents an assembly, while ExternalResource represents a resource file that can be referenced externally through unified resource identifier (URI).
Using the ClientUI application model such as described in the previous section, you can build applications with modular design, which means that an application typically comprised of one or more dependencies. This section explains the relationship of the class models to help you accomplish modular design in your application.
An ApplicationPackage may contain one or more DependencyPackage instances which is defined in the Dependencies property of the application package. The DependencyPackage itself may contain one or more DependencyAssembly instances defined in the Assemblies property of each dependency package. If you have external resources that referenced in your application package, you create one or more ExternalResource instances and add it to the Resources property of the particular application package.
The following illustration explains the relationship between the classes describes above, which forms the complete anatomy of a ClientUI application.
A ClientUI application can be described through a self-describing XML metadata, or through programmatic API using code. There are at least three properties that need to be set to properly describe a ClientUI application such as listed below:
To describe a ClientUI application using XML metadata, you add a new XML file named SAFMetadata.xml to the root folder of your Silverlight project and set its Build Action to Content in the property window. The following example shows the XML metadata that describes a ClientUI application.
SAFMetadata.xml |
Copy Code
|
---|---|
<ApplicationPackage xmlns="http://intersoft.clientui.com/schemas" ID="MyFirstClientUIApplication" Name="MyFirstClientUIApplication" MainType="MyFirstClientUIApplication.MainPage"> </ApplicationPackage> |
A ClientUI application can also be described programmatically in code through the ApplicationPackage class, which is shown in the following example.
C# |
Copy Code
|
---|---|
ApplicationPackage app = new ApplicationPackage(); app.ID = "MyFirstClientUIApplication"; app.Name = "MyFirstClientUIApplication"; app.MainType = "MyFirstClientUIApplication.MainPage"; |
The quickest way to create a ClientUI application is by creating a Visual Studio 2010 project based on ClientUI project template. The most basic project template is the ClientUI Application template, which includes a self-describing XML application metadata, and shell registration in the application startup which is explained later in this topic.
The following figure shows the project files of a new Silverlight application created using ClientUI Application project template.
For more information about ClientUI project templates, see Introduction to ClientUI Project Templates. To create a basic ClientUI application in step-by-step walkthrough, see Walkthrough: Create Your First ClientUI Application.
The advanced features and properties of the class model are explained in the ClientUI Application Framework Features section of this topic. |
ClientUI Application Framework provides a comprehensive class library that allows you to work with a ClientUI application such as described in the previous section. This section provides an overview of the composite application development using the ClientUI Application Framework, and provides best practice and guidance to implement high-performance composite application.
At the center of the ClientUI Application Framework is the UXShell class, which acts as the container for the applications in a composite application, as well as providing a number of application services such as lifetime management, authentication, navigation, windowing and more.
You can think of UXShell as a bootstrapper or lightweight launcher without visual interface, which manages a host of applications that can be downloaded on demand from the web, then install and launch them as requested. The solid architecture of UXShell enables you to design rich applications that consistently run in very minimum load time, even in relatively large business applications. The benefits of the shell architecture are explained later in this topic.
As described in the previous section, a ClientUI application is mapped to an ApplicationPackage which is typically deployed as a .xap file. Using UXShell, you can create a composite application that runs multiple ClientUI applications. An external ClientUI application will be seamlessly loaded and presented to the user interface as if the application were in the same project with the root application.
The following illustration shows a high level overview of a composite application built with UXShell and the class library provided in ClientUI Application Framework.
As seen in the above illustration, a UXShell hosts multiple applications which are defined in the Applications property of the shell. The ApplicationPackage that represents a ClientUI application, which was illustrated in the previous section, is used in the above illustration to show its relationship with UXShell. You can programmatically add a new ApplicationPackage in code, or automatically map them in the high-level application services. These subjects are discussed later in this topic.
Since UXShell is modeled based on shell pattern, it implements low level architecture that propagates application-wide events such as Downloading, Downloaded, Installed, Launched, NetworkOnline and more. Many of these methods are abstracted into IShellManager interface to allow loosely-coupled application design, which separates the actual implementation logic that handles the application events from the ClientUI application model.
To handle the application-wide events in UXShell, you create a class that implements IShellManager interface, then instantiate a new object of that particular class and bind it to the ShellUIManager property of the shell. For more information about implementing the IShellManager to handle application-wide events, see How-to: Implement IShellManager to Handle Application-wide Events.
UXShell extends Silverlight's application service by implementing IApplicationService interface. You generally create only one instance of UXShell to represent a composite ClientUI application.
You typically configure and register the UXShell in the code behind of your App.xaml. This ensures the configuration and services of the shell to be properly started as your application is initialized.
The following example shows how to instantiate and configure the UXShell in the code behind of your App.xaml, and finally register it to the ApplicationLifetimeObjects of the Silverlight application.
C# |
Copy Code
|
---|---|
private void InitializeShell() { UXShell shell = new UXShell(); shell.RootApplication = UXShell.CreateApplicationFromType(typeof(App), ApplicationID, ApplicationID); // Silverlight-specific API this.ApplicationLifetimeObjects.Add(shell); } |
For cross-platform API compatibility with WPF, you may want to consider calling the Register method to register the UXShell in your composite application. Instead of using the approach such as shown in the previous code, you use the following technique which does the same task and supports WPF project at the same time.
C# |
Copy Code
|
---|---|
private void InitializeShell() { UXShell shell = new UXShell(); shell.RootApplication = UXShell.CreateApplicationFromType(typeof(App), ApplicationID, ApplicationID); // Cross-platform compatible API UXShell.Register(this, shell); } |
In many cases, you need to obtain the current UXShell instance that represents your composite application in the application code such as in the code behind of a Page. The UXShell class provides a variety of API to manage the defined applications, such as checking whether an application has been downloaded, or whether an application has been loaded in the domain. More information about the API is explained later in this topic.
To get the current shell instance, you access the Current static property of the UXShell class, such as shown in the following example.
C# |
Copy Code
|
---|---|
if (UXShell.Current.IsApplicationDownloaded(app1)) { MessageBox.Show("Application is already downloaded"); } |
The entire application framework in ClientUI is built on top of solid class library and API which allows you to work with the application programmatically using code.
The following example shows how to create a new ApplicationPackage that represents an external ClientUI application named ExternalClientUIApp1.xap, and add it to the current instance of the shell object.
C# |
Copy Code
|
---|---|
// create a new ApplicationPackage that represents ExternalClientUIApp1 ApplicationPackage app = new ApplicationPackage() { ID = "ExternalClientUIApp1", Name = "ExternalClientUIApp1", Source = new Uri("ExternalClientUIApp1.xap", UriKind.RelativeOrAbsolute), Size = -1 // auto detect the file size at runtime }; // add the application to the UXShell UXShell.Current.Applications.Add(app); |
Once an ApplicationPackage is added to the shell, you can download the application package to be further consumed by other pages in the application.
The following example code shows how to download an application package after it is added to the shell object.
C# |
Copy Code
|
---|---|
// create a new ApplicationPackage that represents ExternalClientUIApp1 ApplicationPackage app = new ApplicationPackage() { ID = "ExternalClientUIApp1", Name = "ExternalClientUIApp1", Source = new Uri("ExternalClientUIApp1.xap", UriKind.RelativeOrAbsolute), EnableMetadataDiscovery = true, Size = -1 // auto detect the file size at runtime }; // add the application to the UXShell UXShell.Current.Applications.Add(app); // download the application app.Download(false); |
An important thing to note in the above example is the use of EnableMetadataDiscovery property. You typically set it to true, so that the application package definition from SAFMetadata.xml in the external package is dispatched and parsed to the particular ApplicationPackage object when the download completes. However, there are certain scenarios where this behavior is not desired, such as in scenario where you already have the complete application package definition which is loaded from database.
UXShell raises application wide events for all operations that it executes. You can intercept these events by creating a class that implements IShellManager interface, and then assign it to the ShellUIManager property of the shell object. For more information about implementing the IShellManager to handle application-wide events, see How-to: Implement IShellManager to Handle Application-wide Events. |
Once an ApplicationPackage has been downloaded, you can create an instance of object which type is specified in the MainType property. The main type and possibly other properties are automatically parsed from the XML application metadata (SAFMetadata.xml) of the particular application, with note that EnableMetadataDiscovery is set to true while performing the download.
The type used as the main type of an application package should be a type that can be injected as a visual child in the Silverlight and WPF visual tree, which commonly derives from FrameworkElement class. |
Continuing the scenario of the previous example which assumes the application package has been downloaded, the following example shows how to get the application using GetApplication method, and then load the application into the current domain context using the Load method, and finally create an instance of the application using CreateInstance method which result is assigned to the Child property of a Border.
C# |
Copy Code
|
---|---|
ApplicationPackage app = UXShell.Current.GetApplication("ExternalClientUIApp1"); if (app != null) { // load the application to the current domain context app.Load(); if (app.IsLoaded) { FrameworkElement element = app.CreateInstance() as FrameworkElement; if (element == null) throw new Exception("Unsupported instance type"); Container.Child = element; } } |
The CreateInstance method performs instance creation in synchronous pipeline call. As opposed, you can use CreateInstanceAsync method to perform the instance creating asynchronously such as shown in the following example.
C# |
Copy Code
|
---|---|
ApplicationPackage app = UXShell.Current.GetApplication("ExternalClientUIApp1"); if (app != null) { // load the application to the current domain context app.Load(); if (app.IsLoaded) { app.CreateInstanceAsync( (resultCallBack) => { InstanceLoaderAsyncResult asyncResult = (InstanceLoaderAsyncResult)resultCallBack; if (asyncResult.IsCompleted) { if (asyncResult.Instance == null) throw new Exception("Unsupported instance type"); else if (asyncResult.Error != null) throw asyncResult.Error; Container.Child = asyncResult.Instance as FrameworkElement; } } , null ); } } |
In addition to working with application and shell using code, the ClientUI Application Framework also provides high-level services that seamlessly consume the class library and shell behind the scene, such as navigation and windowing services explained later in this topic. As a result, you can navigate or load an external application package declaratively in XAML, without the need to write code. |
The quickest way to create a ClientUI application is by creating a Visual Studio 2010 project based on the provided ClientUI project template. The most basic project template is the ClientUI Application template, which includes a self-describing XML application metadata complete with UXShell registration such as discussed in the sub sections above.
For more information about ClientUI project templates, see Introduction to ClientUI Project Templates. To create a basic ClientUI application in step-by-step walkthrough, see Walkthrough: Create Your First ClientUI Application.
ClientUI Application Framework provides built-in extensibility library that allows you to easily design highly extensible Silverlight and WPF applications based on the extensibility best practices and design principles. For more information about the extensibility topics, see Extensibility Pattern Overview.
Each ClientUI application requires a valid runtime licensing to be deployed appropriately. This is true for external ClientUI application that dynamically loaded to the existing composite application. In this case, the runtime licensing is required in the composite/root of the application, and in all application packages that will be loaded on demand.
For more information about application licensing in ClientUI, see Licensing ClientUI for Application Deployment.
In this previous sections, you have learned the fundamental concept of ClientUI application framework, and how to accomplish a variety of tasks related to application management. This section explores further on the high-level features and advanced capabilities in the application framework.
The ClientUI Application Framework provides a comprehensive application lifetime management which is paramount to composite application development. Using classic approach, it is fairly difficult or nearly impossible to consistently keep track of the application state, for example, checking whether a particular application has been downloaded before loaded, and prevents re-download if the application has been downloaded before.
The application lifetime management feature in ClientUI Application Framework streamlines many of these processes and workflows into a solid architecture, thus makes it easy for you to program a composite application that works consistently and reliably.
The following illustration shows the processes and workflows streamlined in the application lifetime management.
As illustrated in the above figure, a ClientUI application has the following workflows when managed in a composite application.
The processes above are automatically handled by ClientUI application framework, given that you have configured the UXShell accordingly.
When the AutoInstallOnDownload is enabled, the downloaded application package is stored to Silverlight's isolated storage. By default, the application framework uses Site storage scope. You can use Application storage scope by setting the shell's InstallStorageScope property to Application. For more information about isolated storage, see Isolated Storage (MSDN Library).
In addition, you can also save and retrieve custom settings that you may want to attach on a particular application. Instead of writing a dozen lines of code to work with isolated settings, you can simply use SaveSetting and GetSetting method provided by the application package. To learn how to use these methods, see How-to: Save and Load an Application-specific Settings.
In certain cases, you may want to achieve specific application management tasks using code. ClientUI Application Framework provides a comprehensive APIs that enable you to accomplish specific tasks programmatically using code.
The following lists several methods available in the UXShell class.
For more information about the members implemented in the shell, see UXShell Class Reference and ApplicationPackage Class Reference.
With ClientUI Application Framework, you can build scalable composite rich web applications that load in a fraction of second. The key is to refactor your applications into smaller, modular dependencies by identifying dependencies and assemblies that are common in the application. The common assemblies can be packaged into a DependencyPackage, which can be easily shared and re-used.
For example, consider a composite application with three large application packages such as illustrated in the following figure.
While building a composite application, you often have scenarios where certain assemblies are commonly used in the other external applications such as reusable UI components. In the scenario above, the three applications contain a total of 8 unique assemblies. In a classic Silverlight application, you may have to download each application entirely. For example, when users request to access the ExternalApp1, your composite application would need to download ExternalApp1 with a total size of 2100 KB. Subsequently, accessing ExternalApp2 requires the package to be downloaded with a size of 2000 KB. Repeatedly, users have to spent unnecessary time and network resources in excess due to poorly designed composite application architecture.
With ClientUI Application Framework, you can refactor your applications into several smaller packages that can be associated as shared dependencies in one or more external ClientUI applications. The shared packages concept in ClientUI Application Framework is centered around two properties, the Shared and SharedID property, which is implemented in BasePackage class. This means that these properties also existed in both ApplicationPackage and DependencyPackage class.
In the above scenario, you can perform the following actions for refactoring purpose:
The following illustration shows the refactored applications based on modular design using ClientUI Application Framework.
To indicate a package as shared, you set the Shared property of the particular package to true. Next, you set the a unique identifier to the SharedID property of the package. The value of the SharedID property is used as main reference for identifying shared dependencies with identical SharedID value. This enables the ClientUI Application Framework to effectively determine whether a shared package has been downloaded, thus eliminates the need to re-download the same package when an external application is being downloaded.
The following XML metadata shows how the Shared and SharedID is used to define dependency packages that are share-able across the three applications as illustrated in the above scenario.
XML Metadata |
Copy Code
|
---|---|
<ApplicationPackage ID="ExternalClientUIApp1" Name="ExternalClientUIApp1" FriendlyName="External ClientUIApp 1" Size="-1"> <Dependencies> <DependencyPackage ID="f37ed107-566a-45c2-b23a-20b27c51d15f" Shared="True" SharedID="SharedAssembly.Main" Source="SharedAssembly.Main.zip" Name="Main SharedAssembly" Size="1000000" Version="1.0.0.1"/> </Dependencies> </ApplicationPackage> <ApplicationPackage ID="ExternalClientUIApp2" Name="ExternalClientUIApp2" FriendlyName="External ClientUIApp 2" Size="-1"> <Dependencies> <DependencyPackage ID="5f02663e-0550-4b16-9ad4-7f349b501c55" Shared="True" SharedID="SharedAssembly.Main" Source="SharedAssembly.Main.zip" Name="Main SharedAssembly" Size="1000000" Version="1.0.0.1"/> </Dependencies> </ApplicationPackage> <ApplicationPackage ID="ExternalClientUIApp3" Name="ExternalClientUIApp3" FriendlyName="External ClientUIApp 3" Size="-1"> <Dependencies> <DependencyPackage ID="16102b60-1e18-4c4c-a0a0-ac6be4de7ffa" Shared="True" SharedID="SharedAssembly.Main" Source="SharedAssembly.Main.zip" Name="Main SharedAssembly" Size="1000000" Version="1.0.0.1"/> </Dependencies> </ApplicationPackage> |
As the application framework intelligently skip downloading shared packages that were previously downloaded, the load time of the external applications is significantly reduced. Using the above scenario, the ExternalApp1 requires to download only 150 KB using ClientUI application framework, as opposed to 2100 KB using traditional approach, while the ExternalApp2 requires to download only 200 KB using ClientUI application framework, as opposed to 2000 KB using traditional approach. The saving ratio between using ClientUI framework and traditional approach is around 1:10.
This section explains the Application Library Caching feature included since Silverlight 3, and how it differs with ClientUI Application Framework.
The Silverlight's Application Library Caching is a deployment feature, and is not an application framework. The application library caching provides a way to cache particular assemblies to your local machine, however, it exposes the following limitations:
For more information about Application Library Caching and its limitations, see Silverlight Application Structure (MSDN Library).
ClientUI Application Framework, on the other hand, overcomes many limitations of the Application Library Caching and at the same time introduces more benefits such as described in the following list:
The application events in ClientUI Application Framework is centered in UXShell class. Unlike UI controls, UXShell does not expose event fields individually in the class for security purpose. Since the UXShell acts as a lightweight container that manages application lifetime and services, it would require you to have specific implementation that handles most of the events according to your business scenario, which eventually drive the event handler design for UXShell.
You can handle the application events raised by the ClientUI Application Framework in two ways such as explained below:
For more information about implementing the IShellManager to handle application events, see How-to: Implement IShellManager to Handle Application-wide Events.
Besides the core class models and infrastructure that built up the entire application framework, ClientUI also ships with high-level application services that take advantage of the application framework to further simplify the composite application development in Silverlight and WPF platform.
For example, you can create a navigation application that allows users to navigate to a page that existed in a different application package as it were navigating to a local page. In most cases, you can achieve this scenario using declarative XAML markup without have to write code.
For more information about application services in ClientUI and its features, see ClientUI Application Services.