ASP.NET VERSIONS: 1.0 |1.1
Deploy Apps With Ease
Leverage the tools in the .NET Framework to create a simple installation process.
By Brian Noyes
ASP.NET makes it easier than ever to build killer Web applications and Web services. But building the app is only part of the battle. Hopefully you'll ship that application someday and put it into production. One of the great capabilities .NET brings to the table is Xcopy deployment - the ability to copy your files into a directory where they're ready to run. That works great for simple applications and deploying patches and updates, but enterprise applications usually have a more complex architecture, requiring a few (or many) more steps to get the application fully deployed to the target server.
At a minimum for a Web application, you need to have the installation process create a virtual directory for you and copy the application files into it. But for enterprise-class Web apps, you likely need to perform additional steps. For example, you might need to register shared components in the Global Assembly Cache (GAC), install databases, add event logs, gather information from the Administrator performing the installation to customize configuration parameters of the install, or run other installers, scripts, or programs as part of the installation process.
To accomplish these tasks you need to do two things. First, plan for deployment early in the design process. Second, package your application for deployment as a Windows Installer project, which will perform all the additional steps needed to deploy your application successfully. In this article, I'll discuss some common considerations for deploying ASP.NET applications and some easy solutions.
Deployment Starts With Design
If your application has any complexity whatsoever, early in your design you need to be thinking about how you plan to deploy it. Know what pieces and parts will make up your application, and what the target production environment will be, both from a hardware and software standpoint. Some of these things might change as your product evolves. So if you keep deployment in mind as you build your app, you can assess how architecture and design changes might impact deployment and decide your course of action.
The tasks you need your .NET application install process to perform generally fall into several categories. The easy part is getting a set of files into the appropriate directories on the target machine. You could accomplish this any number of ways, including simply copying the files over the network or using FTP, or by deploying a compressed file (using WinZip or Microsoft Cabinet) and uncompressing it on the target server.
For ASP.NET, you also need to create a virtual directory or site in IIS. There also might be some form of registration step, which will require you either to register shared assemblies in the GAC or register COM components that will ship with your application. Most real-world applications have you create or update one or more databases and populate them with runtime or configuration data. Finally, you might have other custom processing steps that need to be part of your installation process to execute other installer applications, run administration scripts, create event logs, or countless other tasks.
The most robust way to deploy applications on the Windows platform is to use Microsoft's Windows Installer technology. This means creating a setup program or Microsoft Installer (MSI) file that encapsulates all the steps of the installation process into a single procedure that needs to run on the target machine. MSI files actually are a form of database file, although it has a very complex schema and API for interaction. Using Windows Installer, you also can get automatic support for installation failure and rollback, repair, and uninstall through the Control Panel Add/Remove Programs applet. Visual Studio Setup projects allow you to create an MSI file easily to encapsulate the installation process completely. Web setup projects also handle the creation of the virtual directory in IIS for you.
To register files once they're placed on the target machine, command-line batch files or scripts work nicely if you're performing the install procedures manually; but a Windows Installer package can automate that process for you as part of the installation. Windows Installer packages also let you detect errors in the install process, and you can choose whether to report them to the user or to roll back the installation if the problem is more serious.
Deciding which assemblies should be made shared assemblies can be difficult. If you plan to take advantage of the version-enforcement capabilities in .NET, you'll need to apply strong names to your assemblies whether you make them shared assemblies (by placing them in the GAC) or keep them private (by deploying them in the local application folders). If you go with strongly named assemblies, you might want to use your application configuration file to specify what versions of which assemblies are supported.
Use Visual Studio Setup Projects
VS .NET includes a fairly powerful and easy-to-use capability to create setup projects that you can use to design and compile installation packages for your applications. To create one for an ASP.NET application, simply create a new project and select Web Setup Project from the Setup and Deployment Projects folder in the Project Wizard. If you do this from within a VS .NET solution that contains your Web project, the wizard will pick up some default settings automatically for deploying the Web application contained in the solution. Once the project is created, you can get to all the views containing the various setup steps, properties, and configuration through the context menu for the project. Simply right-click on the project in Solution Explorer and expand the View menu (see Figure 1). For a standard ASP.NET deployment, you should include content files and the primary output in the Web Application folder at a minimum, but you also can include source files, documentation, debug files, and localization resources.
Figure 1. The Project menu for Setup Projects provides access to all the parts of the project you need to manage, including viewing the files installed, Custom Actions, User Interface, Registry settings, and Launch Conditions.
When you place the primary output from a Web application in the Web Application Folder, the setup project creates the \bin subfolder and places the compiled output from the Web application there. It also detects dependencies and places any dependent assemblies that aren't shared into the output \bin folder. Through the views of a setup project and the properties for items in those views, you can fully customize the way the installation behaves and what actions are performed (see Figure 2). You can create a setup project in its own solution, but it works much better if you create a solution that contains both the application you're deploying and the setup project because the setup project can include categories of files from the application project (such as primary output, documentation files, content files, and so on).
Figure 2. You can manage many aspects of your setup project through the Properties window for the objects that compose the setup project, and you can manipulate those objects through one of several views available in a setup project.
Deploying assemblies to the GAC is a simple matter of placing the file in the GAC folder in the File System view of a Visual Studio .NET setup project. Remember that the assemblies you deploy there will require a strong name. If you manage the project that creates the shared assembly separately from the main Web application, you should create a Merge Module setup project for that shared assembly. Then, incorporate the merge module into the main setup project for the Web application so the merge module can be included in other setup projects with minimal configuration. For COM components, there's a Register property for files added to the project so you can have COM components registered on installation automatically.
You'll want to gather additional information frequently from the person performing the installation so you can customize aspects such as which database server to use, account information, and perhaps information to place in an application configuration file. Figure 3 shows you how Visual Studio .NET setup projects let you add dialogs to the setup process using one of many template dialogs. You can name and label the input fields in the dialogs as desired, then pass the values from these fields to custom build steps for further processing.
Figure 3. You can select from one of many form templates to add custom dialogs to the setup process, then you can use the information collected in these forms either to set predefined installer variables or pass information to your custom actions as parameters.
Empower Your Installation Project
The key to a complete installation requires a combination of the ability to specify custom build steps and some form of code to specify what happens in those steps. Visual Studio .NET projects let you create Custom Actions that run for the actions Install, Uninstall, Rollback, and Commit. You could simply execute Windows script or batch files from these actions if you want to code your custom actions as such, but this approach doesn't allow tight integration into the installation process because the scripts or batch file will run outside the transacted environment of the Windows Installer.
There's a very powerful way to accomplish just about anything you might need your installation to do and, unlike many commercial installer products, it doesn't require you to learn any special scripting languages or macros. The .NET Framework includes many classes in the System.Configuration.Install namespace that let you implement Installer classes using .NET languages that can integrate directly into a Windows Installer project.
The code download for this article includes four projects in a solution to demonstrate an example deployment of a Web application (see the Download box for details). First is a simple Web application (DeployTestApp) that has a single Web page that displays a list of customers from a database. Second, there's a class library project (DeployTestBLL) that contains the code that gets the data from the database, representing a business-logic layer for a typical Web application. Third is a Web setup project (DeployTestSetup) that creates the Windows Installer package for creating the Web application on a target machine as well as all the resources it needs. The fourth project (DBInstallerLib) contains the custom installer class that gets called by the Windows Installer package to perform the custom build step.
This application's setup requirements include the ability for the person running the installation to specify the name of the database server, the name of the database to be created, and optionally a username and password if the connection to the database isn't a trusted Windows Authentication connection. The setup program then needs to create the database, populate a table in that database with runtime data, and update the web.config file to include the appropriate connection string for the database once it's created.
To accomplish these steps, you need to create a custom installer class that can run from the Windows Installer process created by the setup project. To create a custom installer class, first create a class library project and include a reference in that project to the System.Configuration.Install.dll library. Then, add a class to the project that derives from the Installer class. You need to place a RunInstaller attribute on this class as well; Figure 4 provides the code. The Installer base class includes the virtual methods Install, Uninstall, Commit, and Rollback, which correspond to the parts of a Windows Installer process. You can override these methods to add custom installation steps to be executed during the overall installation process.
public class DBInstaller : Installer
public override void Install(IDictionary stateSaver)
public override void Uninstall(IDictionary stateSaver)
// Remove resources as necessary
Figure 4. By creating a class derived from Installer, you can include any kind of custom processing in a Windows Installer setup process that you can code in your .NET language of choice.
This article's sample code uses a SQL script for creating the database generated by SQL Enterprise Manager. It reads in the script and executes each command in the script using the SqlCommand class. It then uses the Bulk Copy Program (bcp.exe) utility to import a set of sample data exported from the development database as its deployed runtime data. In this case, it's the Customers table from the Northwind database, but it's created in its own database on the target machine so as not to interfere with your own copy of Northwind.
To run the Bulk Copy Program, you could use the Process class from the System.Diagnostics namespace to execute bcp.exe on the command line. But instead, you can hijack some convenient capability out of the System.VisualBasic namespace - specifically the Interaction class' Shell method. Note that I'm calling this from a C# class library; behold the power of cross-language compatibility in .NET! The Shell method makes it easy to run an application as a fully constructed command line, specify the behavior of the window in which it'll run, and run the application as the interactive user so it can pick up the Windows Authentication identity of that user for something such as logging into SQL Server.
Once the class library with your installer class is built, you can add a custom action to the install process for your setup project and point it to the output of your installer class library. To do this, go to the File System view in the setup project and add the primary output of the class library to a folder in the output of the installation process. (In the code download, I created a Setup subfolder of the Web application and required the setup project to place the output of the installer class library project there.) Now go to the Custom Actions view, right-click on the Install folder, and select Add Custom Action from the context menu. You are presented with a dialog to select executable files and scripts from the output folders of the installation, and you simply can point the action to the class library containing the installer class. Once you've done this, you can set properties for the action, including the CustomActionData property to be passed to the installer or script file as parameters (see Figure 5).
Figure 5. The CustomActionData property for a custom action lets you pass parameters into the custom action. These parameters can be gleaned from the user from custom dialogs in the setup or standard properties such as TARGETDIR.
Using this technique of creating custom actions through Installer-derived classes means you can incorporate any actions you need in your installation process if you can determine how to code it in .NET. You even can throw in Windows Forms to gather further information from the user or to show progress or information regarding your custom actions. The VS .NET setup projects automate the most common actions for you, such as when you place files in locations on the target machine, register shared libraries or COM components, and create virtual directories. There are also some prebuilt installer components for creating Event Logs, Performance Counters, Message Queues, and Services. For more information on using these components, I recommend "Deploying N-Tier Applications with Visual Studio.NET Setup Projects" by Ron Jacobs (http://www.gotdotnet.com/team/xmlentsvcs/deployntier.aspx). If you use Visual Studio .NET Setup projects with custom actions, built-in installer components, and your own Installer-derived classes, there shouldn't be any installation hurdle you can't tackle.
The sample code in this article is available for download.
Brian Noyes is a consultant, trainer, and writer with IDesign Inc. (http://www.idesign.net). Brian specializes in architecture, design, and coding of .NET data-driven Windows and Web applications, and office automation and desktop productivity applications. He's an MCSD with more than 12 years of programming, design, and engineering experience, and he is a contributing editor for asp.netPRO and other publications. E-mail him at mailto:[email protected].
Additional Deployment Options
Deployment is a huge topic and there are countless variations on what the requirements and solutions might be. If you're going to be creating installation packages frequently and allowing end users to install them, you might want to purchase a dedicated installation tool such as one from InstallShield (http://www.installshield.com) or Wise for Visual Studio .NET (http://www.wise.com). For most situations, however, you can get by with the tools in Visual Studio and the .NET Framework - if you know where to look and don't mind writing a little extra .NET code.