ASP.NET Web setup project walkthrough

This post contains a walkthrough that will help you understand the basic tasks to accomplish to create an MSI packages for deploying your web application. The walkthrough describes the most common scenario of deploying a web project.  We will create a standard Web setup project.  This project will generate as output an msi package that will create and configure the application IIS and copy the application’s file to a specific location on the server.   This walkthrough also describes how to modify the web.config file for providing a connectionstring or change any of the configuration sections. 
Because msi packages are mostly deployed by system engineers from the command line, this walkthrough will also pay attention on how to enable quiet installs and how to pass parameters to the installer from the command line.

1.     Create a “Hello World” web service

To be able to create a setup will need a sample project that will be deployed by the setup project.  So we create a new empty ASP.NET website application.
- File->new ->ASP.NET WebService
Add  a Class library project to your solution.
- File->Add->Class Librrary
Now we should have 2 projects inside our solution.
- Add a static method SayHello() to the class1.
Reference this class in your web service project:
- Add Reference-> Projects->SayHelloLibrary
- Change the code of the Hello world method to use the Library static method SayHello()
- Hit F5, your solution should compile. 
- Test the application through the invoke button of the test web page, you should see the following:

2.     Add a Web setup project

We will add the web setup deployment project to the solution.
- File->Add->New Project->Other Project Types->Web Setup Project
Now our solution should look like this:
Now the real work begins, we will configure our web setup project to hold our content and our compiled assemblies.

3.     Add content and assemblies to your web setup project

First we will add the content of our web service project.  These are the asmx pages and the content of the APP_CODE folder.  They will be compiled by the host IIS server the first time the site will be hit.
Right click on the setup project->Add->Project output.
A “Add project output Group” dialog box should appear.
Because our Web setup project does not have any compiled assemblies as output we only can select “Content Files”.   
You should be in the file system view. If you don’t see the above screen.
-  right-click on the web project setup folder and choose view->File system.
Now we will add our web service application compiled assemblies. 
- Right-click again on the web-setup project and choose Add->Project Output and select the SayHelloLibrary project and click on “Primary Output”.
After we click on the ok button Visual studio has added the “Primary Output” to the root of the Web Application Folder. This will result in a compile error the first time we try to hit the application we deploy.
To correct this error we must move the “Primary output” to the Bin folder of our web application. 
- Simply drag & drop the “Primary Output” to the bin folder.
Before we test our first installation package we’ve to compile it because Visual studio will not compile it as part of the solution. When we compile our project, visual studio will generate an msi file containing all parts of our application.
It’s time to test our first installation packet. 
- Select the setup project->richt-click->Install
The setup wizard pops-up, click next.
You can change the default value of the  Virtual directory textbox.  The default Virtual Directory is a property of your “Web application folder” available in the File system view.  Important: If you want to be able of passing the virtual directory as a parameter through the console for a quiet installation you should set this property to a blank field otherwise the msi package will overwrite a blank value with the value of the property.
When the installation is completed successfully the web service should be available on the your local IIS server under the path http://localhost/HelloWorldSetup/service.asmx
The application should also be visible in the “Add or Remove Programs” in the Windows Control Panel.

4. Adapt the connectionString property of the Web.Config file.
The web setup project wizard alow us to change common IIS settings through the File System view (View->File System) by changing the properties of the “Web Application Folder”. 

We can also add prerequisits of our solution (the .net framework2 is a standard prerequisit).
To adapt the connectionString property of our Web.Config file we will have to add custom code to our project that will edit the config file.  To be able to this type of actions during a setup we’ve to create custom actions.  Custom actions are code that is executed during the installation process.  Therefore we’ve to create a new ClassLibrary project. 
- Add a classlibrary project and name it HelloWorldCustomActions.
- Add following assemblys references: System.Configuration.dll,
System.Configuration.Install.dll, System.Web.dll.
- Add a new class to MyCustomAction.cs your project that will be used during the installation of your project.    This class must inherit from “System.Configuration.Install.Installer” class and be annotated with the RunInstaller(True) attribute. using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration.Install;
using System.ComponentModel; 
namespace HelloWorldCustomActions
    publicoverridevoid Install(System.Collections.IDictionary stateSaver)       
    {            base.Install(stateSaver);       
Now we need to create our custom action and associate it with our class.
First we need to add the output of the HelloWorldCustomActions assembly in our Setup project.
- Right-click “HelloWorldSetup” project->Add->Primary Output
- From the File System View move the “Primary output from HelloWorld actions” to the bin folder.
Now we will make sure that our code is executed as a custom action during the installation.
- Right-click the project folder->view->CustomActions.
The Custom action view should be displayed.
- Right-click on the install folder->Add Custom Action->select “Primary output from HelloWorldCustomActions (Active)”.
The web setup project wizard contains a form where the user must select the application site and the virtual directory. To be able to locate and change the web.config file of our application we need to read these parameters.  We can also pass these arguments by the command line and provide a targetdirectory. 
To be able to access these parameters we need to declare them in the “CustomActionData” property of our CustomAction: 
- Select your custom action->In the property window select “CustomActionData” Insert the following values:
/targetdir="[TARGETDIR]\" /targetvdir="[TARGETVDIR]" /targetsite="[TARGETSITE]" /targetconn="[EDITA1]"  /db="[DB]"
We will now add a screen to our wizard that prompts the user for a connectionString. 
- Right click the project->View ->User Interface.
- Right click start-> Add Dialog
- Select Textboxes(A) and move it between “Installation Address” and “Confirm Installation”.
- Set the following properties:
Now we will code our custom action.
- First check you have following references in you CustomAction project.
- Set following using statements in your CustomAction class:
using System;
using System.Configuration;
using System.Configuration.Install;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.DirectoryServices;
using System.Web.Configuration;
using System.Windows.Forms;
your install method should look like:
 publicoverridevoid Install(System.Collections.IDictionary stateSaver)       
{            base.Install(stateSaver);
              // Retrieve configuration settings            string targetSite = Context.Parameters["targetsite"];
            string targetVDir = Context.Parameters["targetvdir"];
            string targetDirectory = Context.Parameters["targetdir"];
string targetConnectionString = Context.Parameters["targetconn"];
            //if this is a quiet install //the connectionstring is passed as with a parameter named "db"
            if (targetConnectionString.Length < 1)                targetConnectionString = Context.Parameters["db"];
              if (targetConnectionString.Length < 1)thrownewInstallException("Please provide a connectionstring!");
              if (targetSite == null)thrownewInstallException("IIS Site Name Not Specified!");
              if (targetSite.StartsWith("/LM/"))                targetSite = targetSite.Substring(4);  ConfigureWebConfig(targetSite, targetVDir, targetConnectionString);

Add the ConfigureWebConfig method:
 void ConfigureWebConfig(string targetSite, string targetVDir, string targetConn)       
{            // Retrieve "Friendly Site Name" from IIS for TargetSite
            DirectoryEntry entry =                 newDirectoryEntry("IIS://LocalHost/" + targetSite);            string friendlySiteName =                 entry.Properties["ServerComment"].Value.ToString();
              // Open Application's Web.Config            Configuration config =                 WebConfigurationManager.OpenWebConfiguration("/" + targetVDir, friendlySiteName);
              addConnectionStringAttribute(targetConn, config);            togleCompilationAttribute(config);
              // Persist web.config settings            config.Save();
Method to add the connectionstring to your web.config:
privatestaticvoid addConnectionStringAttribute(string connectionStringValue, Configuration config)       
{            ConnectionStringSettings appDatabase = newConnectionStringSettings();
            appDatabase.Name = "db";            appDatabase.ConnectionString = connectionStringValue;
            appDatabase.ProviderName = "System.Data.SqlClient";

This method will set the compilation attribute to debug=false
privatestaticvoid togleCompilationAttribute(Configuration config)       
{            CompilationSection compilation;            compilation = config.GetSection("system.web/compilation") asCompilationSection;
              if (compilation != null)                compilation.Debug = !compilation.Debug;
Now you can test your installation package. 
- Right-click Setup project->Install.

The second screen should ask for a connectionstring.
5.     Quiet install
When distributing a setup package you will mostly install the application through a quiet install.  Therefore you’ve to pass the parameter through the command line.   I experienced that the parameters you pass through the console are sometimes overwritten by the parameters you’ve added in your custom screens.  This is why I added a supplementary parameter “db” and don’t use the parameter “targetconn”.  The installer first checks if the parameter is empty.  This will be the case if you install the application through a quiet install. 
You will find this parameter in the CustomactionData property of the custom action:
/targetdir="[TARGETDIR]\" /targetvdir="[TARGETVDIR]" /targetsite="[TARGETSITE]" /targetconn="[EDITA1]"  /db="[DB]"
 The code that handles the parameter in the Install method:
if (targetConnectionString.Length < 1)
                targetConnectionString = Context.Parameters["db"];
You can launch the msi setup package with the folowing command line: (First navigate to the directory containing the builded release version of the msi)
>HelloWorldSetup.msi /qb targetvdir="HelloWorld" db="Test for connectionstring"
If you want to specify the target website you need to specify the website IIS metabase targetsite path.  This path mostly begins with “/LM/W3SVC/” followed by the site id. 
A trick to find the site id or to debug the setup application is to use the /l* option.  Launch the installer with the /l* option and follow the wizard.  The /l* will log all the parameters passed to the installation program.  After the installation completes you can retrieve website metabase path by searching for the “targetsite” in the log file.
>HelloWorldSetup.msi /l* log.txt
I hope this tutorial help you to understand the basics of creating a web setup project.  This type of setup will enable you creating testable and repeatable deployment scenarios.  It will also help our IT engineers to deploy web applications gracefully on production machines.

View Geoffrey Vandiest's profile on LinkedIn

Add comment