Choosing Between ClickOnce and Windows Installer
Xambi Solutions, Inc.
Summary: Michael Sanford takes an in-depth look at the .NET Framework 2.0 ClickOnce technology and compares it with the existing Windows Installer technology. Michael concludes by making some recommendations on when to use each technology. (15 printed pages)
Windows Installer Overview
Products, Features, and Components
Windows Installer Features
How to Choose?
Use Both Windows Installer and ClickOnce
One of the most exciting features demo'ed at the 2004 PDC was the new ClickOnce deployment technology. With an impressive feature set, ClickOnce is certain to be a popular technique for deploying applications, but what about Windows Installer? In this article, we'll delve into the features of ClickOnce and highlight the key differences between the two technologies along the way. Finally, we'll provide some guidance on when each of these deployment technologies should be used.
Microsoft first introduced Windows Installer in 1999 in response to customer feedback about the challenges faced when deploying applications. Specifically, they pointed out the following weaknesses in existing installation technologies:
- They failed to consistently and reliably manage shared resources such as COM Components, ActiveX controls, and so on. This issue is commonly referred as "DLL Hell".
- They failed to provide standard customization capabilities.
- They did not provide a way for an application to repair or maintain itself once it was installed.
- They failed to provide a mechanism to allow parts of an application to be installed on demand.
- They failed to provide a consistent mechanism for the installation to interact with the operating system.
Windows Installer is a system-level component included in all operating systems starting with Windows 2000. Where traditional installation technologies relied on proprietary scripts and file formats, Windows Installer uses an open, database-like file format to describe an application, its resources, and the operations required to successfully install it. The internal structure of the database format, including its standard table and column definitions, can be found in the Windows Installer section of the Platform SDK. The latest version of the SDK can be found at http://www.microsoft.com/msdownload/platformsdk/sdkupdate/.
Windows Installer packages are stored in a file with an "msi" file extension. While the format of these files is a proprietary implementation based on OLE structured storage, the content of an msi file is easily accessible using tools provided with the Platform SDK. The primary msi editing tool provided by the Platform SDK is code-named "Orca". As seen in Figure 1 below, the logical structure of an msi file is quite similar to that of a relational database.
Figure 1. Viewing the contents of an msi file with Orca
In addition to the tools provided by the Platform SDK, there are several third-party tools available that dramatically ease the task of msi authoring, and administration. A few of the major vendors are:
- InstallShield (http://www.installshield.com)
- Wise (http://www.wise.com)
- Zero G (http://www.zerog.com)
Windows Installer packages rely on a logical structure of Products, Features, and Components to divide an application into cohesive units of functionality. Features are the lowest-level entity with which a user can interact with the installation, while components are the lowest-level entity that the installation developer works with. For example, a graphics application might consist of two features: a core application feature that installs the application's executable (.exe), and a clip-art feature that installs an optional collection of clipart. The core feature of our fictitious installation might be comprised of two components. The first component might act as a container of the application's primary executable file and the registry entries it depends on to start up properly. The second component of the core feature might include a shared .dll and the COM registration information that must be recorded in the registry for the COM sub-system to recognize it.
Windows Installer is a complex technology with a significant number of customization and configuration capabilities. Exploring all the features of Windows Installer is beyond the scope of this article. Instead, we'll take a quick look at some of the more significant features.
Windows Installer provides a robust set of APIs and a complete Automation Interface that allow applications to interact with Windows Installer, both as a part of the authoring process and as part of the installation and maintenance process.
The runtime behavior of an installation package can be customized in a number of different ways. For example, an installation can be developed with support for setting specific options on the command line, or a special Transform File can be created that actually modifies the contents of the msi file at installation time, thereby changing the behavior of the installation. The Platform SDK and most third-party tool vendors provide support for creating Transform Files.
- Install On Demand
Windows Installer supports a concept known as advertising, which allows individual parts of an application (or the entire application) to be installed only when the user needs it. Through deep integration with the operating system, Windows Installer is able to detect when an application, or a specific feature of an application, is needed. For example, if an application is installed that is capable of editing .foo files, Windows Installer will check to be sure the app is installed and install it if needed when the user double-clicks a .foo file in Windows Explorer.
Similar to the way Windows Installer is able to install an application or feature on demand, it is also able to repair an application as the user interacts with it. For example, when a user causes an application to be run by clicking a Start Menu shortcut, or double-clicking an associated file, Windows Installer is able to intercept the request and verify that the appropriate elements of the application are properly installed. If a problem is detected, a repair will occur before the application is run.
- Transactional Installation
Much of the inner workings of Windows Installer is devoted to ensuring that running an install won't adversely affect your system if something critical fails during the installation. Windows Installer accomplishes this by creating an internal "script" of exactly what must be done to properly install the application. If something goes wrong during the installation, the script can essentially reverse any actions that have been taken, thereby leaving the system in its original state.
- Source Resiliency
An important aspect of the ability of Windows Installer to repair an application after it has been installed is that at times, it will need access to a copy of the original installation source. For example, if Windows Installer determines that a critical file is missing or corrupted, it needs to get a clean copy of that file. Source Resiliency is a mechanism that allows Windows Installer to search in multiple locations to find the original installation and then to prompt the user for the media if it cannot be found at any other location. Source locations can be the local file system, a network share, or an Internet URL. Windows Installer 3.0 has also enhanced these capabilities, allowing administrators to more easily manage source locations.
- Upgrades and Patching
A typical product lifecycle does not end after the application has been successfully installed. As nice as that would be, the reality is that most applications need to be updated or patched to deploy fixes or new features. Windows Installer supports the creation and distribution of byte-level patches for deploying hotfixes and upgrades for distributing more comprehensive application updates. Windows Installer 3.0 has introduced significant improvements to patching by supporting patch sequencing and the ability to uninstall patches.
- Managed Environment Support
In large corporate environments, systems are often locked down to prevent users from installing rogue applications and putting the integrity of that system at risk. Windows Installer includes several features that allow certain msi-based installs to be "blessed" by the System Administrator to run in this type of locked-down environment.
ClickOnce is a brand new deployment technology that ships as a part of the .NET Framework version 2.0 and was first demo'ed at PDC 2004 in Los Angeles. ClickOnce is focused on bringing the simplicity of Web application deployment to smart client applications, while providing a secure runtime environment. To deploy an application with ClickOnce, you simply need to place the application files on a Web server, file share, or the local file system and provide the user with a link to the application manifest.
If you are developing with Visual Studio 2005, publishing an application with ClickOnce is a trivial task, thanks to the Publish Wizard. To access the Publish Wizard, simply right-click the project name in the Solution Explorer, then select Publish from the context menu. Alternatively, you can access the Wizard from the Publish tab of the Project Properties dialog box.
Figure 2. Visual Studio 2005 Publishing Wizard
A ClickOnce deployment is controlled through the use of two XML manifest files: a deployment manifest and an application manifest.
The deployment manifest is used to describe the application's deployment. It includes the location of the application manifest, files described in the application manifest, and the version of the most current release that clients should be running.
<?xml version="1.0" encoding="utf-8"?> <asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns="urn:schemas- microsoft-com:asm.v2" xmlns:asmv1="urn:schemas-microsoft- com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <assemblyIdentity name="My Test App.application" version="18.104.22.168" publicKeyToken="7726c4d654f5bf83" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft -com:asm.v1" /> <description asmv2:publisher="Xambi Solutions" asmv2:product="My Test App" asmv2:supportUrl="http://michael -dev2/WindowsApplication1/Support.htm" xmlns="urn:schemas -microsoft-com:asm.v1" /> <deployment install="true"> <subscription> <update> <expiration maximumAge="3" unit="days" /> </update> </subscription> <deploymentProvider codebase="http://michael_dev2/WindowsApplication1/My%20Test%20App .application" /> </deployment> <dependency> <dependentAssembly codebase="My Test App_22.214.171.124\My Test App.exe.manifest" size="4908"> <assemblyIdentity name="My Test App.exe" version="126.96.36.199" publicKeyToken="7726c4d654f5bf83" language="neutral" processorArchitecture="msil" /> <hash> <dsig:Transforms> <dsig:Transform Algorithm="urn:schemas-microsoft -com:HashTransforms.Identity" /> </dsig:Transforms> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <dsig:DigestValue>GANTD3FaR5KJiqnEluecM05wtss=</dsig:DigestValue> </hash> </dependentAssembly> </dependency> <Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#" /> <!-- Details Omitted for Brevity --> </asmv1:assembly>
The application manifest is used to describe the application, assemblies, files, resources, and permissions required for the application to function properly. Additionally, the application manifest also dictates the location where updates will be located.
<?xml version="1.0" encoding="utf-8"?> <asmv1:assembly manifestVersion="1.0" xsi:schemaLocation="urn:schemas-microsoft -com:asm.v1 assembly.adaptive.xsd" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns="urn:schemas -microsoft-com:asm.v2" xmlns:asmv1="urn:schemas-microsoft -com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <asmv1:assemblyIdentity name="My Test App.exe" version="188.8.131.52" publicKeyToken="7726c4d654f5bf83" language="neutral" processorArchitecture="msil" type="win32" /> <asmv2:configuration configFile="My Test App.exe.config" xmlns="urn:schemas-microsoft-com:asm.v1" /> <entryPoint> <assemblyIdentity name="My Test App" version="184.108.40.206" publicKeyToken="7726C4D654F5BF83" language="neutral" processorArchitecture="msil" /> <commandLine file="My Test App.exe" parameters="" /> </entryPoint> <trustInfo> <security> <applicationRequestMinimum> <PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /> <IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Access="Open" /> <IPermission class="System.Security.Permissions.IsolatedStorageFilePermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Allowed="DomainIsolationByUser" UserQuota="10240" /> <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="Execution" /> <IPermission class="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Window="SafeTopLevelWindows" Clipboard="OwnClipboard" /> <IPermission class="System.Windows.Forms.WebBrowserPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Level="Restricted" /> <IPermission class="System.Drawing.Printing.PrintingPermission, System.Drawing, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" version="1" Level="SafePrinting"/> </PermissionSet> <defaultAssemblyRequest permissionSetReference="Custom" /> </applicationRequestMinimum> </security> </trustInfo> <dependency> <dependentAssembly codebase="My Test App.exe" size="12288"> <assemblyIdentity name="My Test App" version="220.127.116.11" publicKeyToken="7726C4D654F5BF83" language="neutral" processorArchitecture="msil" /> <hash> <dsig:Transforms> <dsig:Transform Algorithm="urn:schemas-microsoft -com:HashTransforms.Identity" /> </dsig:Transforms> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <dsig:DigestValue>xx4Nai4Nr7Bp5R7xtyqO8gAVsSk=</dsig:DigestValue> </hash> </dependentAssembly> </dependency> <dependency> <dependentAssembly preRequisite="true"> <assemblyIdentity name="Microsoft-Windows-CLRCoreComp" version="2.0.3600.0" /> </dependentAssembly> </dependency> <file name="My Test App.exe.config" size="1222"> <hash> <dsig:Transforms> <dsig:Transform Algorithm="urn:schemas-microsoft -com:HashTransforms.Identity" /> </dsig:Transforms> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <dsig:DigestValue>BdHEVcmEBWqRZGitWdDZ/vAGGmQ=</dsig:DigestValue> </hash> </file> <Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"> <!-- Details Omitted for Brevity --> </Signature> </asmv1:assembly>
After the application and deployment manifests have been created, they simply need to be copied to the deployment location, along with the required application files. It is important to note that the deployment manifest need not be stored in the same location as the application manifest. For example, the deployment manifest can be shipped on a physical disc. When activated, the deployment manifest will tell the ClickOnce engine where to find the application manifest. This is an important feature of ClickOnce, as it allows you to ensure that users get the latest version of your application from the very first install, rather than installing a version from disc, then immediately requiring an update.
When the user launches your application, ClickOnce will install or update your application according to the settings contained in your deployment manifest. If your app requires elevated permissions, the user will be asked to grant the required permissions:
Figure 3. The user is queried about required permissions
Clicking the More Information link in the lower-right corner of this dialog will result in the informational dialog shown below.
Figure 4. More information about the security warning
And finally, once the application is up and running, we can see in the title bar where the app was deployed from and a special icon overlaying the applications icon. When we hover our mouse pointer over this icon, we can see a special message indicating the security context in which the application is running.
Figure 5. Informational message about the security environment
Note When writing .NET applications that may run in a secure environment, it is very important that security exceptions be explicitly handled to ensure that the application remains stable and that the user understands what has happened when a security exception occurs.
Now that I've taken a quick look at features of both Windows Installer and ClickOnce, you will note that each technology was quite different goals. To further illustrate this point, consider the following matrix:
|Associate File Extensions||X||X|
|Install to GAC||X|
|Write to Registry||X|
|Install-time User Interaction||X|
|Install for All Users||X|
|Custom Actions at Install/Uninstall||X|
|Installation Conditions/System Interrogation||X|
|Auto-Update and Scheduling||X|
|Download/Install Assemblies on Demand||X|
|Rollback to Previous Version||X|
As I mentioned earlier, each of these technologies was designed and developed with a completely different set of goals. Neither is intended to replace the other. ClickOnce offers a very compelling set of features, most of which are not found in Windows Installer technology. These features are specifically targeted at developers building .NET Framework-based smart client applications that don't have sophisticated configuration requirements. Windows Installer is a much broader deployment technology that is inherently designed to be extensible and able to handle any deployment challenge, including .NET applications.
When it comes to your choice in deployment technologies, you don't need to limit yourself to just one option. The key is to choose the right tool for the right job. While there is no single rule or simple answer, there are some general guidelines you can use to help make the best decision for your specific needs.
- Does the application install any COM components?
- Does the application require registering any components for COM-Interop?
- Does the application install any services?
- Does the application have to install to a specific location or to the Global Assembly Cache (GAC)?
- Does the application have any components that are conditionally installed, based on the operating system or runtime environment?
- Does the application require user input at installation time?
- Does the application require configuration of system-level services such as Active Directory or COM+?
- After the application is installed, does it create files, write to the registry, or affect the system in some way that would leave resources behind when the application is removed?
If you answered yes to any of these questions, then today Windows Installer is the best choice for your needs. However, if you don't need to address the scenarios described in the list above, then ClickOnce is an excellent candidate for your deployment solution. If you want to leverage the distinct benefits provided by ClickOnce, then understanding the capabilities of ClickOnce early in your application design process is critical. Deploying an early version of an application with ClickOnce, but then belatedly realizing a need to move to Windows Installer, would create a difficult upgrade path that can be avoided through careful up-front planning.
Yes, that's right! You heard me correctly. Now that I've built a case for how different these two technologies are in their implementation, I am going to shake up your world by telling how you can use them together.
Windows Installer provides advanced capabilities for interacting with the user during an installation. Oftentimes, this is a critical step in the deployment process. The ability of an installation to interrogate the target system to ensure that it meets the minimum requirements of the application is critical. Additionally, most applications tend to have some interaction with the operating environment. This may include writing log files to disk, storing data in the registry, etc. A well-behaved application needs the opportunity to clean up this application-specific data when it is removed from the system. All of these are key deployment concepts missing from the ClickOnce paradigm.
In contrast, Windows Installer has an update and patching story, but it's not nearly as sleek and easy to manage as that of ClickOnce.
With a little thought, planning, and ingenuity, we can leverage both technologies to create a deployment model with the best of both worlds.
Designing the Windows Installer Setup
The basic concept here is to create an outer install based on Windows Installer technology. This outer install takes on the responsibility of inspecting and interrogating the system before the app is installed. It can interact with the user and gather and store configuration information, install shared assemblies to the GAC, and so forth. At uninstall time, it takes on the responsibility of cleaning up resources that ordinarily would have been left behind by our application. For example, it can uninstall files, delete log files create at runtime, uninstall services, remove assemblies from the GAC, and so on.
Plugging our ClickOnce application into our install is again a fairly simple task. Since ClickOnce apps can be activated via an Internet or intranet URL, we can simply create a shortcut on the target system that points to the application manifest. To accomplish this, we can use Windows Installer to create a .url file on the fly at install time. A .url file is a special type of shortcut that complies with the standard .ini file format.
Using Windows Installer to create this INI file, we only need to add a single row to the IniFile table.
|FileName||My App.url||The name of the .url file. The main part of this name is what the user will see. In this case, the shortcut will display "My App".|
|DirProperty||MyShortcutFolder||The primary key name of a directory defined in the install. This identifies the location where the shortcut will be created.|
|Section||InternetShortcut||The main section being written into the ini file.|
|Key||URL||Key portion of the key/value pair.|
|Value||http://www.myserver.com/myapp/v1_0/myapp.application||The actual URL to the application manifest.|
|Action||0||A value of 0 indicates that the value should be created or updated if it already exists.|
|Component||MyComponent||A reference to the component that is responsible for the install/uninstall of our shortcut.|
A well-designed implementation of this technique will require further modifications to our msi file to ensure our installation is accomplishing all the tasks required by our application, but I hope this has provided you a glimpse of what is possible when you leverage the best parts of each deployment technology.
For applications that aren't restricted by their functional limitations, ClickOnce is an excellent deployment technology that provides valuable benefits and an updating model that was previously available only to Web-based applications. For applications with more sophisticated requirements, Windows Installer remains the deployment technology of choice. Each of these deployment technologies shares the common goal of reliably installing your application, but the similarities end there. You can be sure that the capabilities of ClickOnce will grow in the future, but you can be equally sure that Windows Installer is here to stay. In the meantime, get creative and learn to love them both!
About the Author
Michael Sanford is President and Chief Software Architect for Xambi Solutions (http://www.xambi.com). Prior to forming Xambi, Michael was President and CEO of ActiveInstall Corporation, which was acquired by Zero G Software. ActiveInstall achieved notoriety for its Windows Installer Authoring solutions. Michael is a Microsoft Certified Solution Developer (MCSD), Microsoft Certified Systems Engineer (MCSE), and a Windows Installer MVP. You can read Michael's Blog at http://msmvps.com/michael.