Virtual Developer Workshop: Containerized Development with Docker
In the early days of personal computing, constructing an application that could be installed successfully on another computer was often as simple as compiling an .exe file and copying it to a floppy disk. As applications have become increasingly complex and sophisticated, the number of files needed for a typical installation has grown from a handful of files to several hundreds.
This is especially true with Windows applications, which have historically required sophisticated setup programs to copy the correct dynamic link libraries (DLLs) and support files to the end user's computer and to register the applications appropriately with the operating system. This first of a two-article series discusses the features provided by the .NET Framework for deploying Windows applications onto the end user's machine. To this end, it discusses the different types of deployment options the .NET Framework provides. It also takes a look at the architecture of the Windows Installer and then goes on to discuss the differences between XCOPY and Windows Installer. Along the way, it demonstrates the process of packaging up Windows forms applications using the setup and deployment project types supported by Visual Studio.NET.
Setup Versus Deployment
Before you can understand the processes involved in setting up and deploying applications, you need to understand the difference between setup and deployment. A setup is an application or process that allows you to package up your application into an easy-to-deploy format, which then can be used to install the application on another machine. Deployment is the process of taking the application and installing it in on another machine, usually by using a setup application.
Planning for Deployment
At one time or another, most computer users have experienced the dark side of installing Windows programs. For example, in the pre-.NET era, when you installed a new version of your Windows application, the installation program copied the new version of your DLLs into the system directory and made all the necessary Registry changes. This installation could impact other applications running on the machine, especially if an existing application was using the shared version of the installed component. If the installed component was backward compatible with the previous versions, then it was fine. In many cases, however, backward compatibility may be impossible to maintain. If you cannot maintain backward compatibility, you often end up breaking the existing applications as a result of new installations.
One of the areas Visual Studio .NET was designed to address was the installation shortcomings of Windows applications that relied heavily on COM components. Visual Studio .NET can simplify the installation process because Visual Studio .NET applications rely on .NET assemblies (which are built on a completely different programming model) for much of their functionality. In addition, Visual Studio .NET applications compile as assemblies, a deployment unit consisting of one or more files.
To fully understand how Visual Studio .NET simplifies the deployment process, take a brief look at the structure of the assembly that provides for this simplification. Assemblies contain four elements:
- MSIL (Microsoft Intermediate Language) code—Language code (C#, VB.NET, and others) is compiled into this intermediate common language that can be understand by the common language runtime (CLR).
- Metadata—Contains information about the types, methods, and other elements defined in the code
- Manifest—Contains name and version information, a list of included files in the assembly, security information, and so on
- Non-executable content, such as supporting files and resources
As you can see, assemblies are so comprehensive and self-describing that Visual Studio .NET applications don't need to be registered with the Registry. This means that Visual Studio .NET applications can be installed by simply copying the required files to the target machine that has the .NET Framework installed. This is called XCOPY installation. However, it is also possible to automate the setup process by making use of the deployment projects that Visual Studio .NET provides. The next section examines Visual Studio .NET's various deployment options.
.NET Deployment Options
You can deploy Windows forms applications using any one of the following two deployment options:
- XCOPY deployment
- Deployment using Visual Studio .NET Installer
The following sections discuss both these deployment options and explains when to use each.
Using XCOPY for Deploying Applications
The .NET framework simplifies deployment by enabling XCOPY deployment. Prior to .NET, installing a component required copying the component to the appropriate directories and making the appropriate Registry entries. But with XCOPY deployment, all you have to do to install the component is copy the assembly into the bin directory of the client application. The application will be able to start using it right away because of the self-describing nature of the assembly. This is possible because compilers in the .NET framework embed identifiers or metadata into compiled modules, and the CLR uses this information to load the appropriate version of the assemblies. The identifiers contain all the information required to load and run modules and to locate all the other modules referenced by the assembly.
An XCOPY deployment is also called a zero-impact install because the way you configure the Registry entries and the component does not impact the machine. This zero-impact installation also makes it possible to uninstall a component without affecting the system in any manner. All you need to do is remove the specific files from the specific directory.
Using Visual Studio .NET Installer for Deploying Applications
Even though XCOPY deployment is very easy to use, it does not lend itself well to all deployment requirements. For example, if your application has more robust setup and deployment requirements, Visual Studio .NET Installer is a better option. Because Visual Studio .NET Installer is built on top of Windows Installer technology, it takes advantage of Windows Installer's features. To learn about Visual Studio .NET Installer, look first at the architecture of Windows Installer.
Windows Installer Architecture
Windows Installer is a software installation and configuration service that ships with the Windows 2000 and Windows XP operating systems. It also is freely available to all Win9x and NT4 platforms. Windows Installer Service maintains a record of information about every application that it installs. The Windows Installer runtime (MSI) inspects these records during the execution of deployment packages. When you uninstall an application, Windows Installer checks the records to make sure that no other applications rely on its components before removing it.
Windows Installer divides applications into the following three categories:
- Product—A product is something a user can install. For example, MS Word is a product.
- Feature—A feature is the smallest unit of functionality in a product. A product is composed of multiple features. For example, the AutoCorrect functionality can be considered a feature of MS Word.
- Component—A component is the smallest unit that multiple features can share. A component in Windows Installer terms is not the same as a component in the .NET Framework. A Windows Installer component can be a single file or multiple files that logically belong together. It can be an executable, a DLL, or a simple text file. A collection of components can join together to provide a feature, and a component also can be shared across multiple features. Whereas features are specific to a product and identified by a name unique only within the product, components are global across all products installed on a machine. For example, the spell checker component of MS Word can be shared across all the applications that want to implement spell-checking.
Information related to a product, such as features and components, are described in a centralized repository known as the Installation Database. The Installation Database is nothing but a file with the extension .msi that not only contains information about the features and components of the product but also about the sequence of user interfaces displayed during the installation of the product. Because the Windows Installer is registered as the default application for files with an .msi extension, the shell automatically invokes it when a user opens an .msi file. When invoked in this way, the installer reads product information from the Installation Database file and determines whether the product is already installed. If the product is not yet installed, it launches the product's installation sequence, which is described in the database. If the product is installed, different logic is invoked, such as adding and removing features or uninstalling the product.
Additional Visual Studio .NET Features
In addition to the Windows Installer, the deployment projects in Visual Studio .NET also provide the following features:
- Reading or writing of Registry keys
- Enables creating directories in the Windows file system
- Provides a mechanism to register both COM components and .NET components (in the GAC)
- Gathers information from the users during installation
- Enables setting launch conditions, such as checking the user name, computer name, current operating system, software application installed, presence of .NET CLR, and so forth
- Enables running a custom setup program or script after installation
You will take an in-depth look at all the above-mentioned features when you create deployment projects using Visual Studio .NET in an upcoming section of this article.
Trade Offs Between XCOPY and Windows Installer
As you can see, XCOPY is ideal for deployment scenarios that are simple and manually executed. However, many scenarios require a more robust deployment solution. In those cases, you should use the Windows Installer technology to install applications. The following advantages make Windows Installer ideal for creating setups and deployments for .NET applications:
- If an application installed with Windows Installer gets corrupted, it can perform a self-repair using the repair feature of Windows Installer packages. In XCOPY-based deployments, you need to manually replace the corrupted component with the newer version.
- The automatic rollback feature not only ensures that the installed components are uninstalled but also brings the machine back to the stage it was prior to the installer starting, if the installation fails.
- Because Windows Installer uses an MSI installation database for storing all the information, you can get the information about which files are copied, which Registry keys are created, and so on.
- If you're developing an application that you want to distribute to multiple users (or sell as a package), you can automate the entire installation process using Windows Installer's sophisticated installer technology—thereby simplifying the deployment.
Visual Studio .NET Deployment Project Templates
Visual Studio .NET comes bundled with five types of project templates that you can use to set up and deploy .NET applications. You can access these project templates the same way you would any other project in Visual Studio .NET, by using the File | New Project dialog box.
Figure 1: Setup and Deployment Project Types Available in Visual Studio .NET
Figure 1 shows the different setup and deployment project types available in Visual Studio .NET. Take a brief look at each of the available project types:
- Setup Project template—Use the Setup Project template to create a standard Windows Installer setup for a Visual Studio .NET application.
- Web Setup Project template—Use the Web Setup Project template to create a Windows Installer setup program that can be used to install a Web application onto a virtual directory of a Web server.
- Merge Module Project template—Merge modules enable a set of files to be packaged up into an easy-to-use file that can be re-used and shared between setup programs that are based on Windows Installer technology. The idea is to package all the files and any other resources that are dependent on each other into the merge module. As you can imagine, this type of project can be very useful for packaging a component and all its dependencies into a single unit, which then can be merged into the setup program of each application that uses the component. During the installation, the merge module component is installed only if the component is not present on the machine. The merge module Windows installer package files are identified by the file extension .msm. For example, the latest versions of MSXML (Microsoft XML) Parser are also available in the form merge modules. If your application uses MSXML Parser, you can easily package the merge module into the setup program of your application.
- Setup Wizard template—Use the Setup Wizard to guide you through the process of creating one of the above setup and deployment project templates.
- Cab Project template—You use the Cab Project template to create a cabinet file (.cab). A cabinet file can contain any number of files, but no installation logic. It is generally used to package components into a single file, which can then be deployed on a Web server to enable the browser-based clients to download these components onto their local machines before installing them. For example, controls hosted on a Web page are often packaged up into a cabinet file and placed on the Web server. When the browser encounters the control, it verifies that the control isn't already installed in the local computer, at which point it downloads the cabinet file, extracts the control from it, and installs it onto the user's computer.
Creating an Installer Package
Now that you know the different setup project types, you can learn the steps involved in creating a setup and deployment project for a Windows application. During this example, you will create a simple Windows application and see how to deploy it. The application, named FormattingApplication, simply allows you to format the contents entered in a rich textbox. Because the main focus of this article is on creating Windows Installer packages, you will not spend too much time on this. However, you should download the source code for this project along with the support material on the final page of this article.
Start by adding a Windows Installer project to the solution that contains the C# formatting application project. Now, add a setup project to your existing solution by selecting File-> Add Project-> New Project from the New Project dialog box. Name the project FormattingApplicationSetup.
Configuring Deployment Properties
Now that you've created the project, you can configure its deployment-related properties. Right click on the FormattingApplicationSetup project from the Solution Explorer and select Properties. Then, open the Configuration Properties tree view and select Build. Click the Configuration Manager command button to bring up the Configuration Manager dialog box. Now, change the Active Solution Configuration setting from Debug to Release for both the projects to create a Release build. Also, check the Build option for the setup project. By setting the configuration settings to Release, you create a release build that can be installed onto the end user's computer.
When you work with a VS.NET project, by default, you create a Debug build that creates the debugging information as part of the project output. The project output also is also not optimized for performance. Before deploying the application, change the Debug build to Release, which not only optimizes the project output for performance but also ignores the unnecessary debugging information.
After modification, the dialog box should look like Figure 2. Click Close.
Figure 2: Configuration Manager Dialog Box After Modification
The deployment project files can be packaged into any one of the following three formats:
- Loose uncompressed files—No compression takes place, and the entire program and data files are stored as they are.
- Setup file—When selected, this option merges all the files and compresses them into an MSI file.
- Cabinet file(s)—All files are packaged into one or more cabinet files. The MSI file contains entries about all the project .cab files, and it uses that information at runtime to load and install the .cab files. These files will be placed in the same directory as the MSI file.
In this case, because you want to compress all the files into a single MSI file, select the option In Setup file. Next, you need to configure the BootStrapper property. Set this property to Bootstrapper. A bootstrapper is a program that must be executed before the actual application can be run. When you install the application created with Visual Studio .NET Installer, it requires that Windows Installer version 1.5 be present on the target computer. The Windows XP operating system is the first operating system that comes bundled with Windows Installer 1.5. If you want to deploy your application on earlier systems, you need to include the bootstrapper as part of the installation program. If you include this option, it increases the file size by about 3MB. Because you want to include the bootstrapper to support earlier systems, you select that option.
If you are deploying your application only on Windows XP-based systems, you can safely ignore this option, thereby decreasing the size of the final installation program. If you use the Web Bootstrapper option, you need to make the bootstrapper available for download over the Web, as it isn't included in the MSI download. When selecting this option, you will be asked to provide the URL of the download. The user installing the application that installs the bootstrapper will use this URL. The main benefit to this approach is that no additional space is required in the installation package, which reduces the size of the install.
Finally, set the Compression property to Optimized for speed, which installs the files to be compressed faster.
Configuring Project Properties
Apart from setting the configuration properties for the entire solution, you also need to set the following deployment-specific properties for the deployment project, FormattingApplicationSetup. These properties are accessed through the Properties window. The following list discusses some of the important properties that can be set for a deployment project:
- AddRemoveProgramsIcon—Specifies the icon to be displayed in the Add/Remove Programs dialog box on the target computer
- Author—Allows you to specify the name of the application's author
- Description—Allows you to specify the description that is displayed during the installation
- Keywords—Specifies the keywords that can be used to search for an installer on the target machine
- DetectNewerInstalledVersion—Allows you to specify whether you want to check for newer versions of the application during the installation
- RemovePreviousVersions—Allows you to indicate whether you want to remove the previous versions of the application during the installation
- Manufacturer—Specifies the name of the application's manufacturer
- ManufacturerUrl—URL of the manufacturer's Web site
- ProductCode—Specifies a unique identifier (GUID) for the application
- ProductName—Name of the product
- SupportUrl—URL for the Web site that contains support information about the application
- Title—Title for the installer
- Version—Specifies the version number of the installer
After making the above changes, the FormattingApplicationSetup properties window looks like Figure 3.
Figure 3. FormattingApplicationSetup Properties Window After Configuration
Now that you understand the different properties that need to be configured, you can learn about the core component of setup and deployment projects that provides the foundation for performing advanced deployment-related configurations.
Different Types of Setup Editors
Because the deployment projects in Visual Studio .NET offer a great deal of flexibility, you very easily can specify how and where a solution will be deployed. Because the bulk of an installer's work is copying files to the right places, the setup editors obviously each contain a file system configuration editor. However, a setup also can include Registry configuration options, checking for special conditions, and so on. The ability to customize the installer's user interface is also useful. For this reason, VS .NET includes a number of editors within the setup projects.
The following editors can all be accessed through the View | Editors menu:
- File System Editor—Adds files and shortcuts, such as Start menu items, to the installation package
- Registry Editor—Manipulate Registry entries on the target computer
- File Types Editor—Associates file extensions with applications; useful in cases when your application uses custom file extensions and you want to associate a specific application with that file extension
- User Interface Editor—Configures the dialogs that are shown during the installation
- Custom Actions Editor—Starts external programs during installs and uninstalls
- Launch Conditions Editor—Specifies the requirements for your application to be installed on the target computer
Part 2 of this article series will take an in-depth look at all of the above editors.
What You've Learned
Part 1 of this article series taught you the different ways of deploying a Windows application and then identified when to use which deployment option. It also demonstrated the configurations that are required before creating an installer package. To this end, you used the project properties of a Setup and Deployment project and saw how these properties play an important role in the creation of an installer package. Part 2 will explore the different types of editors provided by the deployment project and then demonstrate how to deploy the installer project onto the target machines.