Chapter 1: The "Longhorn" Application Model
Chapter 1: The "Longhorn" Application Model
Brent Rector
Wise Owl Consulting
October 2003
Contents
Features of the "Longhorn" Application Model
The Application Class
The NavigationApplication Class
Extensible Application Markup Language (XAML)
Summary
Why do we need a new application model? One major reason is to bridge the gap between developing an application for Microsoft® Windows® and developing an application for the Web.
Today when you write a Windows application, you can take advantage of Windows features. Your application can provide a rich, responsive user interface. You can install the application on the client computer, which allows the application to run offline, without a network connection. Windows applications can take advantage of the hardware capabilities of the client computer.
However, traditional Windows applications also have a number of drawbacks. You typically must install a Windows application. This makes the application and any updates hard to deploy. Windows applications don't run in the browser. Therefore, familiar Web UI paradigms such as page-oriented applications, navigation directly from one page to another, page history, and more aren't available to your application unless you create them from scratch. Windows applications also don't support text very well, especially when you try to mix text and graphics on the same page. Creating a Windows application that automatically flows text around graphics and that responds to user-initiated changes in the window size and user preferences for fonts and readability is a huge amount of work.
Web applications have their own distinct strengths as well. When you browse to a Web page, the browser downloads only that page and the components the page requires. When you navigate to a new page, the browser then downloads the new page's requirements. In other words, the browser progressively downloads the application as needed.
Deployment of a Web application is trivial. What deployment? You place the necessary application components on a server, and the browser downloads them as needed. There's no deployment per se.
Creating the UI for a Web application is also quite easy. You declare your intentions using markup. For example, suppose I want a table in a specific position. I want an image to follow the table. I want some text to flow around the image. Mixing text, graphics, and media (sound and video) in a Web application is straightforward.
Of course, Web applications also have their bad points. You can't install a Web application on the desktop system; therefore, the application cannot run offline. You must always have a connection to the server. Certain application operations require roundtrips to the server, and that lessens performance. A Web application selection of controls is quite primitive in comparison to the available Windows controls. A Web application therefore typically has poor interactivity. It's also hard to develop an attractive UI for a Web application because you must express any non- trivial layout using tables.
Currently, developers designing new applications need to make an initial, huge, irreversible decision: should the application be a Web-style application or a classic Microsoft Win32® application? Completely separate programming models (and skills!) are needed depending on which application model you choose.
"Longhorn" allows you to develop applications using the best of both worlds. The "Longhorn" application model takes the best features of Web applications and the best features of Windows applications and combines them in a single unified programming model based on managed code.
A second major reason for developing a new application model is to provide a single programming model that can create the wide variety of "applications" in use today. Look at one of your favorite Web sites, such as CNN or MSNBC. Is the Web site a traditional application? Is it a document? Is it a multimedia presentation? In many cases, the answer is yes to all three questions.
When a Web site includes UI elements such as list boxes, edit controls, and radio buttons, it looks like an application presenting a UI. However, when it displays images and text flowing around the images, the Web site is similar to a document. When it presents Flash content, graphics, audio, video, and animation, the Web site seems to be a multimedia presentation.
Of course, such rich Web sites are difficult to develop. You need to patch together an HTML markup–based description of the page, with Microsoft ActiveX® controls for a rich UI, with embedded Flash animations, and possibly using Portable Document Format (PDF) for document support. All these technologies use a different architecture, provide different performance characteristics, and require different programming models and tools.
This typically means that you must hire multiple developers with different skill sets to develop each portion of the application. The developers must then merge the different models into a single working application. Developing the application is hard enough. Debugging it is often a nightmare.
"Longhorn" provides a unified architecture that supports these three tiers—documents, applications, and media. Do you want to create your UI declaratively using markup? Go for it. Do you need to use rich Windows controls? Then do so! Do you want to write event handlers in a strongly typed, managed language? You can do that as well. Do you want to mix text, graphics, and video in a document with intelligent layout and presentation according to the user's preferences and optimized for best viewing and reading on the client system? Guess what? You get that too.
The "Longhorn" application model makes it possible to write an application using a single programming model that supports application-style UI functionality, document-style presentation of text and graphics, and integration of various media. In addition, you can create the UI using markup like a Web application. You also get the deployment (or lack of deployment) ease of a Web application. However, you still have the performance and ability to install the application for offline use like a Windows application. Your application can run as a stand-alone application or hosted in a Web browser by simply recompiling one source code base. In either case, your application can be form-based, like many traditional Windows applications, or page- based, like Web applications.
Features of the "Longhorn" Application Model
The "Longhorn" application model defines what an application is:
- Its entry points
- Its flow of control—how to navigate from one page to another
- Its shared state and resources
- Application-wide events
- Its isolation from other applications
The "Longhorn" application model defines how to deploy and maintain an application:
- Deployment as single or multiple files
- Update, rollback, and administration
The "Longhorn" application model defines the user's experience with the application:
- Zero-impact installation
- Stand-alone (Windows-style) or integrated in browser
- Runs online or offline
- Navigation model
"Longhorn" Web Applications
The "Longhorn" application model allows you to write a rich application similarly to the way you write today's Web applications. This provides an easy migration path for Web developers, as the code they write is similar to the code for dynamic HTML (DHTML) Web pages. They can (shudder) place markup and script in same file. They can deploy the files for the application to a Web server. The application pages run in the Web browser.
However, the object model for a "Longhorn" Web-style application is much simpler and far more powerful than DHTML. The application code can use the complete "Longhorn" presentation layer. Therefore, a "Longhorn" Web application can use rich client controls, support multimedia and graphics on the page, handle events locally—basically everything a normal client application might do. In fact, a "Longhorn" Web application isn't much different from a "Longhorn" desktop application other than that the files live on a server; a browser typically, but not necessarily, hosts the UI; and the application runs with restricted permissions because the user hasn't installed it on the client system.
"Longhorn" Desktop Applications
The "Longhorn" application model also defines how to write desktop applications. A "Longhorn" desktop application is an application that the user has installed locally. Such applications can run online or offline. Such applications can register with the shell, place icons on the desktop, add shortcuts to the Start menu, and more.
A desktop application can also run in the browser window or in a stand-alone window. In fact, a desktop application can support many features traditionally associated with a Web application, including the following:
- Explicitly define external entry points—that is, can start on any page
- Share state across pages
- Handle various events, including page navigation events
- Control application flow
- Add/remove entries from a page history/travel navigation log
- Launch application windows
Building a "Longhorn" Application
To build a "Longhorn" application, you define the object model for your application. You can define the model programmatically by writing code or declaratively by writing markup in a language called the Extensible Application Markup Language (XAML). You compile your code and/or markup into one or more .NET assemblies, an application manifest file, and a deployment manifest file.
Optionally, you can package your application into a new file format, called a container. The application files in a container can be compressed, encrypted, and digitally signed.
I discuss building a "Longhorn" application in detail in Chapter 2, but for now the main idea is that building a "Longhorn" application gives you the application's code, an application manifest that describes all the components that the application uses, and a deployment manifest that tells the system how to install and maintain the application.
Deploying a "Longhorn" Application
The "Longhorn" application model provides for easy, cost-effective deployment of your application. In the simplest case, you simply copy the application files to a server. Similarly, installing your application is straightforward and non-impactful.
One option is not to install the application at all. The user can browse to the application manifest on a server and run it. "Longhorn" incrementally downloads your application and executes it. You get no confirmation demands, no reboot requirements, and no DLL hell. In fact, you do not even need Administrator rights to install or run the application.
Alternatively, the user can browse to the application's deployment manifest on the server and run it. "Longhorn" incrementally downloads your application, installs it, and executes it. By default, all "Longhorn" applications run in a limited permission environment called the Secure Execution Environment (SEE).
Applications running in the SEE receive a restricted permission set that is roughly equivalent to the permissions granted to today's applications associated with the Internet zone. An application that requires additional permissions than "Longhorn" provides by default must request those additional permissions in its application manifest.
The first time the user runs such an application, the "Longhorn" Trust Manager will evaluate the elevated permission request, notify the user of a suggested risk level associated with granting the application's permission request, and provide a suggested response for that risk level. When the user permits the Trust Manager to grant the application its requested permissions, the Trust Manager records this information. Subsequent executions of the installed application proceed without the security warning.
Today, when you install an application locally, it receives the FullTrust permission set simply because it loads from the LocalComputer zone. Code Access Security (CAS) works differently for "Longhorn" applications. A local (or installed) application runs under the security policy of the site from which the user downloaded it instead of automatically receiving FullTrust simply because it is installed locally.
When loading an application, its components, and its resources, "Longhorn" provides evidence to the common language runtime (CLR) security system such as
- Internet zone and site of origin (from the Uniform Resource Identifier [URI])
- Publisher and module name (from the deployment manifest)
CAS then provides security policy–based enforcement over access privileges based on the application's evidence.
The deployment manifest for an application can specify the update interval that "Longhorn" should use when checking for a new version of the application. When "Longhorn" detects that a new version is available, it downloads and installs the new version in the background. The next time the user runs the application, she receives the new version.
When installing an application, "Longhorn" preserves the previous version, if any. Should you need to, you can painlessly roll back to the previous version or even completely uninstall the application using Add/Remove Programs. IT departments can push the installation of an application to a client system for a hands-free deployment.
You specify how to deploy the application when you compile the project, and you can change the deployment scenario by recompiling, typically with few or no changes to your source code.
A developer's program initially interacts with much of the "Longhorn" application support via an instance of the MSAvalon.Windows.Application class, so let's look at that class.
The Application Class
A "Longhorn" program always contains a single instance of an application object. This object derives directly or indirectly from the MSAvalon.Windows.Application class and performs the following functions:
- Provides an entry point, encapsulation, and scope for the application
- Allows an application to share code and state across the pages that make up the application
- Provides application-level events
- Maintains a collection of the application's windows
- Provides a security model
- Defines any resources that the application uses
The MSAvalon.Windows.Application class provides basic application support to an application. You typically use it when your application needs low overhead and does not use page navigation features. However, most "Longhorn" platform applications use the closely related MSAvalon.Windows.NavigationApplication class, which inherits from MSAvalon.Windows.Application and adds support for navigation. I'll discuss the NavigationApplication class in detail in the following section. You will typically define a class that inherits the appropriate base class, overrides base class methods as necessary, and then registers for events to provide custom startup or shutdown procedures.
The SimpleApplication1.cs source file listing, shown here, demonstrates using the Application object. The EntryClass.Main method creates my specialized application object, MyApp, and calls its Run method to launch the application. The MyApp class overrides the OnStartingUp method, which receives control when the application is starting up. When the system invokes the OnStartingUp method, I call a helper method that creates the application's main window, adds some text to the window, and displays the window.
SimpleApplication1.cs
using System;
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Media;
namespace IntroLonghorn {
public class MyApp : MSAvalon.Windows.Application {
MSAvalon.Windows.Controls.SimpleText txtElement;
MSAvalon.Windows.Window mainWindow;
protected override void OnStartingUp (StartingUpCancelEventArgs e) {
base.OnStartingUp (e);
CreateAndShowMainWindow ();
}
private void CreateAndShowMainWindow () {
// Create the application's main window
mainWindow = new MSAvalon.Windows.Window ();
// Add a dark red, 14 point, "Hello World!" text element
txtElement = new MSAvalon.Windows.Controls.SimpleText ();
txtElement.Text = "Hello World!";
txtElement.Foreground = new
MSAvalon.Windows.Media.SolidColorBrush (Colors.DarkRed);
txtElement.FontSize = new FontSize (14,
FontSizeType.Point);
mainWindow.Children.Add (txtElement);
mainWindow.Show ();
}
}
internal sealed class EntryClass {
[System.STAThread]
private static void Main () {
MyApp app = new MyApp ();
app.Run ();
}
}
}
I used the following command line to compile the SimpleApplication1.cs source code into an executable application. You might need to adjust the paths to the referenced assemblies.
csc /r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationCore.dll
/r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationFramework.dll
/r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\WindowsBase.dll
SimpleApplication1.cs
The Application class contains a number of other useful properties, methods, and events. For example, your application class can override the OnShuttingDown virtual method to provide custom shutdown behavior. The application class also provides the StartingUp and ShuttingDown events so that other classes can register for startup and shutdown notifications. The Shutdown method allows you to initiate the shutdown of the application programmatically.
You might want to reference your application object from multiple places in your source code. Therefore, the Application class provides the Current static property that returns a reference to your application object. The following code fragment uses the Current property to locate the application object and register for a shutdown event notification:
MyApp app = (MyApp) MSAvalon.Windows.Application.Current;
app.ShuttingDown += new
Application.ShuttingDownEventHandler (ShutDownHandler);
§
private static void
ShutDownHandler (object sender, MSAvalon.Windows.ShuttingDownEventArgs e) {
§
}
The NavigationApplication Class
When you want navigation support for your application, you'll typically use the MSAvalon.Windows.Navigation.NavigationApplication class, which extends the MSAvalon.Windows.Application class. Although you can build a navigation-based application without using the NavigationApplication class, using the class provides the following additional capabilities to your application:
- Simplifies writing navigation-based applications; not usually necessary to subclass the class
- Determines when a connection is available
- Provides navigation events—such as Navigating, NavigationProcess, Navigated, NavigationError, LoadCompleted, and Stopped—which it fires when the appropriate event occurs in any of the application's windows
- Shares state across pages
- Provides a container for property values shared across pages
- Implements a policy that opens an initial window by default
Externally, a navigation application's user can navigate only to well-defined entry points of the application. Internally, however, the developer controls navigation by hooking events. You can determine when a window or frame attempts to navigate to a new page and when the navigation is complete. You can cancel or redirect any navigation. You can find out the identity of the target page. You can handle navigation errors.
The familiar navigation model makes an application easy to use. A navigation application provides behavior similar to the Web. Your application can use hyperlinks, provide Forward and Back buttons, display a Favorites list, and maintain a page History. The "Longhorn" NavigationApplication class and related classes provide all the support for such features.
A navigation application works whether online or offline, and it works the same whether a browser hosts the application or the application runs as a stand-alone. In addition, you have complete control over this Weblike behavior. You can customize the user experience as required. You can insert, remove, and modify Travelog entries to control where the Forward and Back operations go. You can define which pages (entry points) are logged in the History.
A navigation application typically creates one or more instances of the MSAvalon.Windows.Navigation.NavigationWindow class. The SimpleApplication2.cs listing, shown here, demonstrates a use of these classes. This listing is the same as SimpleApplication1.cs except that it uses the NavigationApplication and NavigationWindow classes.
SimpleApplication2.cs
using System;
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Media;
using MSAvalon.Windows.Navigation;
namespace IntroLonghorn {
public class MyApp : MSAvalon.Windows.Navigation.NavigationApplication {
protected override void OnStartingUp (StartingUpCancelEventArgs e) {
base.OnStartingUp (e);
CreateAndShowMainWindow ();
}
private void CreateAndShowMainWindow () {
// Create the application's main window
mainWindow = new MSAvalon.Windows.Navigation.NavigationWindow ();
// Fill window with appropriate controls
§
// Show the window
mainWindow.Show ();
}
}
internal sealed class EntryClass {
[System.STAThread]
private static void Main () {
MyApp app = new MyApp ();
app.Run ();
}
}
}
The code you've seen up to now is just another variation on traditional programming models. The only new aspect is the actual classes I've used. Most of the time, however, you won't actually write much of this code. Let's take a slight detour and learn about a new programming language that allows you to write this same code in a much more compact and—to me, at least—more understandable manner.
Extensible Application Markup Language (XAML)
In many applications, much of the code you write pertains to creating and updating the UI of the application. In fact, in the previous examples, there was no code other than that required to create the UI. In the last few years, many developers have learned to write, and even to prefer to define, an application's UI by using one of a number of available markup languages. The "Longhorn" platform defines a new markup language named the Extensible Application Markup Language (XAML; pronounced "Zamel," which rhymes with "camel").
Using a markup language to define a UI has a number of advantages over using a procedural programming language. These advantages include the following:
- More apparent control hierarchies
- More apparent property inheritance
- Easier processing and interpretation of markup language by tools
- Potential separation of UI and procedural code
I like XAML, and I prefer to use it to define my UIs rather than using the procedural-type coding I've shown you so far in this chapter. However, don't think that you'll be able to do everything you'll need to by using nothing but XAML.
Consider this statement from the documentation: "Documents can often be written entirely in XAML and displayed in the browser." I hastily point out that this sentence uses the word documents, not applications, and it qualifies the statement with the term often. When you're writing a document that displays static content, you can create it in pure XAML. You can even write a document that uses data binding to display and update content from a data source by using nothing but XAML. You can define animations and mouse-over effects by using nothing but XAML. You can do a heck of a lot using nothing but XAML. (In fact, I try to do as much as possible in XAML and as little as possible in code. My applications seem to be less buggy and work more quickly the less code I write!) Nevertheless, to write a production application, you'll typically need to react to events, provide custom decision logic, or include many other non-UI operations, so you'll need to mix XAML and code. Fortunately, this is extremely easy to do.
I'll describe XAML files in more depth in Chapter 3; for now, let's look at a primer for XAML:
- A XAML element name is a .NET Framework class name. When you define a XAML element, you are effectively creating an instance of the .NET Framework class with the same name as the XAML element.
- A XAML attribute name maps to the property or field with the same name, typically in the class instance.
In the SimpleApplication1.cs program, I create a window and add some controls to it by using the following code:
// Create the application's main window
mainWindow = new MSAvalon.Windows.Window ();
// Add a dark red, 14 point, "Hello World!" text element
txtElement = new MSAvalon.Windows.Controls.SimpleText ();
txtElement.Text = "Hello World!";
txtElement.Foreground = new
MSAvalon.Windows.Media.SolidColorBrush (Colors.DarkRed);
txtElement.FontSize = new FontSize (14, FontSizeType.Point);
mainWindow.Children.Add (txtElement);
mainWindow.Show ();
The following XAML document produces exactly this same UI.
HelloWorld.xaml
<Window xmlns="https://schemas.microsoft.com/2003/xaml" Visible="true">
<SimpleText Foreground="DarkRed" FontSize="14">Hello World!</SimpleText>
</Window>
The root Window element creates an instance of a class named MSAvalon.Windows.Window. Somehow, the build system needs to know that the XAML element named Window refers to an instance of the class named MSAvalon.Windows.Window. The xmlns attribute value provides this mapping.
XML parsers interpret unqualified element names relative to the namespace specified in the most-recent, in-scope, default namespace attribute, xmlns. When you specify an xmlns value of "https://schemas.microsoft.com/2003/xaml", the build system interprets an unqualified element name on the defining element, or one of its subordinate elements, as the name of a class in a predefined set of namespaces.
Let me restate that in more concrete terms, using C# as an example. The xmlns declaration effectively adds a number of using statements to your code. The build system then interprets each unqualified XAML element name as a class name with the using declarations providing the context for the possible namespaces. Although the list might change, at the time of this writing, specifying the standard value for the default namespace attribute causes inclusion of the following using statements:
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Controls.Primitives;
using MSAvalon.Windows.Data;
using MSAvalon.Windows.Documents;
using MSAvalon.Windows.Shapes;
using MSAvalon.Windows.Media;
using MSAvalon.Windows.Media.Animation;
using MSAvalon.Windows.Navigation;
The standard default namespace declaration also causes the build system to reference the PresentationFramework and PresentationCore assemblies, which contain classes in the previously listed namespaces.
I set the Visible attribute of the Window element to true. This corresponds to my original code that displays the window by calling its Show method.
I've nested a SimpleText element within the Window element definition. This tells the system to instantiate an MSAvalon.Windows.Controls.SimpleText object, make it a child of the Window object, and set the value of the simple text object to the "Hello World!" string.
Save the preceding XAML code in a file named HelloWorld.xaml, and run the file. The browser will interpret the XAML code in the file and display the UI, as shown in Figure 1-1.
Figure 1-1. The browser displaying the XAML version of Hello World (click picture to see larger image)
You might want to use a .NET class that isn't defined in one of the default namespaces listed previously. A typical example is using a class from an assembly that you create. The build system needs to be able to map the element name that you specify in the XAML source file to the appropriate .NET class in the correct assembly. XAML defines an XML processing instruction (PI) named ?Mapping that you use to make this association.
The ?Mapping PI allows you to define an XML namespace prefix that maps to a CLR namespace and assembly. When you qualify an XAML element name with this namespace prefix, you tell the build system, in effect, to take the element name, add the CLR prefix to the name, and create an instance of the class with the resulting name. The compiler will reference the specified assembly so that it can find the definition of the class.
The following example creates an instance of the WiseOwl.Statistics.PoissonDeviate class, the definition of which resides in the WiseOwl.Statistics.Library assembly:
<?Mapping XmlNamespace="stat" ClrNamespace="WiseOwl.Statistics"
Assembly="WiseOwl.Statistics.Library" ?>
<Window xmlns="https://schemas.microsoft.com/2003/xaml" Visible="true">
<SimpleText Foreground="DarkRed" FontSize="14">Hello World!</SimpleText>
<stat:PoissonDeviate Mean="5.0" />
</Window>
I cannot emphasize enough that XAML is simply another way to produce code that uses the .NET Framework UI classes. In fact, you could have a tool that displays a XAML UI specification graphically using a visual designer. Another tool might do the reverse and allow you to design the UI graphically and save it as a XAML file. Yet another tool might save the UI design as procedural code, which is similar to how the WinForms designer works. All these approaches are just different methods of specifying the same information.
Earlier in this chapter, I mentioned that the browser could render a XAML file in its window. The browser can do this only when the XAML file contains nothing but markup, like the simple example just shown. As your UI becomes more complicated, you'll typically have to use event handlers and other nonmarkup source code in addition to the XAML that describes the UI. Any time you have a mixed source code base—that is, markup and nonmarkup source code—you must compile the markup and source code using the MSBuild utility. After compilation, you can run the application as a stand-alone component or have the browser display the resulting UI.
Summary
All right! You now understand the basics of the new application model. You've learned how to use markup to create a UI declaratively, albeit a very simple UI. You could write the equivalent of Web pages using XAML files and deploy those files to a server for a user to browse. However, scenarios that are more interesting will typically require you to compile the application before deploying it. So let's jump right in and learn how to build and deploy a "Longhorn" application.
Continue to Chapter 2: Building a "Longhorn" Application.
© 2003 Microsoft Corporation. All rights reserved.
IntelliSense, Microsoft, MSDN, MS-DOS, Visual Basic .NET, and Visual Studio .NET are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Other product and company names mentioned herein may be the trademarks of their respective owners.