Installing a Web Application to an Existing IIS Website using Wix3

[article]
Summary:

This article describes a detailed procedure for installing a new web application on an existing IIS website, when Wix3 is used to create the msi file. This can be a common requirement in a large deployment. However, I find it's a lot of work to actually get it done,

This article describes a detailed procedure for installing a new web application on an existing IIS website, when Wix3 is used to create the msi file. This can be a common requirement in a large deployment. However, I find it's a lot of work to actually get it done,

1    The Requirement
The SFS application I am working on used to have a fixed installation directory under the Default Web Site which is "C:\inetput\wwwroot\SFS". And one day we got a message from our deployment team:

Installing a new (or existing) web application into our Production cluster may seem like a simple thing, but believe me, there are a variety of things that make it just complex enough to need to be explained and just complex enough that the MSI you create to install an application needs to be smarter than you think.

  1. First of all, an application gets installed into a web site.  Our Production servers have more than one web site on them:  Intranet, Extranet, Public, etc.  When your setup program tries to install itself, if it does not specify a particular web site it will "choose" the first one that it gets from IIS.  This is most likely the Default Web Site, but not always, and, depending upon the accessibility of the application (Extranet vs. Intranet) it may not even be the correct site.  If it is not the correct site we have to try and move it from one site to another, but any special configuration that may have occurred may not be moved over causing no end of grief for both you and us.  As a result, your setup program needs to query IIS with regard to the web sites that are available and provide a drop down list to the person doing the installation so that they can pick the correct site.
  2. Next, an application needs to tell us which Virtual Directory it needs to get installed in.  Pretty straight forward.  Your setup program needs to prompt for this with the default being where you are expecting it to be.
  3. OK, next step, application pool.  While applications don't need their own application pool it makes things a lot easier to troubleshoot and manage if they do.  As a result, the setup program needs to prompt for the Application Pool that the application should be using after it is installed.
  4. Also finished.  If your setup program makes changes to config files based on the environment (thank you!!!) then you need to provide a list of environments for which you can make changes.  A drop down list, a set of radio buttons, anything that allows us to pick an environment would be preferred as opposed to a free form text field.  If it is free form , do you want "Production", "PROD", "Prod" or "P"?  Things should be as simple as possible.
  5. Last thing:  is there some way to run your MSI in an automated fashion, without human intervention?  What if we used a different process for installing your application and had automated deployments set up for 4:00 AM.  How do we set all of the parameters for your application?  Can it be done?  Think about it.

And below was the sample screen they gave me:

jhaug09-1.jpg

Note: To install in the root directory of the selected website, leave the Virtual Directory field empty. Or, you can specify the Virtual Directory to create/update a virtual directory under the selected website.

2    Microsoft Fix
Microsoft actually released a fix to provide a solution for this problem:
"FIX: You cannot deploy a Web Setup project to Web sites by using host headers or IP addresses in Visual Studio 2003 or in Visual Studio 2002 Service Pack 1"
http://support.microsoft.com/default.aspx?scid=kb;en-us;821335

However, after a bit of experimenting, I found that fix probably only applied to those Web Setup projects created from Visual Studio. In our case, the msi file is created by Wix. That javascript doesn't work on our msi file, no matter how I try to recompile our project with that new DPCA.dll.

3    The Wix Solution
So I was on my own. After some hard work searching on Internet, I figured out this procedure to get the job done. Here is what needs to be changed to our existing Wix code:

  1. First I need to create a new dialog for this screen.
  2. Then I need to add the new dialog to our standard installation sequence. This dialog will be added right after the Welcome dialog and before the InstallDir dialog, because we need to change the installation path in InstallDir Dialog.
  3. We need to display all existing IIS websites in the new dialog. Assume a Custom Action to be run right before the new dialog is created.
  4. After the user picks a website, we need to find out its root directory to be used as the installation path in the InstallDir dialog. Assume another Custom Action can do this job.

Please note in the following sample, I borrowed a lot of source code from various places on the Internet. To list a few:

  1. Vallery's Post: http://osdir.com/ml/windows.devel.wix.user/2005-07/msg00020.html
  2. Alex's Wix Blog: http://blogs.technet.com/alexshev/archive/2008/02/21/from-msi-to-wix-part-5-custom-actions.aspx

3.1    The New Dialog: ConfigSFSDlg
Below is my prototype code for this dialog. I have to add the hidden ComboBox with an item, otherwise the ComboBox doesn't appear in the msi table, and the Custom Action won't work. It will be good to fix this issue, but I am still new to Wix and my knowledge in msi is very limited. I've already ordered this book and hopefully that can help me out: "The Definitive Guide to Windows Installer", by Phil Wilson.
jhaug09-2small.jpg

In this dialog, the edit box allows user to enter the new virtual directory to be created under an existing website. The ComboBox with property name called "TARGETWEBCOMBO" will be used to display all websites as shown below. The content of TARGETWEBCOMBO will be filled in from the Custom Action 1.
jhaug09-3.jpg

3.2    Custom Action 1: Display Websites
The hard work of finding all existing websites is done by the following Custom Action called caDisplayWebSites. It retrieves information of existing website from local machine and modifies the msi table.

This is a Type 6 Custom Action. Alex's blog has some good examples for all types of Custom Actions: http://blogs.technet.com/alexshev/archive/2008/02/21/from-msi-to-wix-part-5-custom-actions.aspxjhaug09-4small.jpg

3.3    Custom Action2: Find the Website Root Directory
Once the user picks one of the websites in ConfigSFSDlg dialog, we need to find out the root directory of this website, in order to install our new application SFS underneath it. For example, in the screen below, the user picks the website called OnlineGuilde and specified a new virtual directory SFS:jhaug09-5.jpg

The job to find out the website root directory is done by another custom action called caReturnWebSiteRootPath as shown below:
jhaug09-6small.jpg

Please note that I have to manipulate the "Default Web Site" differently because of that hidden ComboBox we have in the new dialog. It will be good if I can clean up these mess.

3.4    Custom Action 3: Set the Install Path
Custom Action 3 "SetSFSInstallPath2" set the installation path to the new website's root directory.

It is a Type 35 Custom Action which many say it should be replaced by a Type 51 Custom Action.

"Be Careful or Even Avoid Using Type 35 Custom Actions": http://blogs.msdn.com/heaths/archive/2006/06/14/be-careful-or-even-avoid-using-type-35-custom-actions.aspx
jhaug09-7small.jpg

3.5    The InstallDirDlg
As shown below, the new application will be installed to a new virtual directory under the picked website root directory plus the new virtual directory if there is any:
jhaug09-8.jpg

3.6    Three Ways about Sequence
The real difficult part is to find out how to properly queue the new dialog and these two Custom Actions in the installation sequence. After tons of reading and experiments, finally I got it work in one way. The right sequence we want is like this:

WelcomeDlg --> Custom Action 1 --> ConfigSFSDlg --> Custom Action 2 --> Custom Action 3 --> InstallDirDlg

  1. Custom Action 1 finds the websites.
  2. ConfigSFSDlg displays the websites, and user picks one of them.
  3. Custom Action 2 finds the picked website's root directory.
  4. Custom Action 3 will set the installation path under the website's root directory.
  5. InstallDirDlg displays the path the new application will be installed to.

    jhaug09-9.jpg
jhaug09-10small.jpg

3.6.1    In the Sequence Tables
We'll queue our Custom Actions in InstallUISequence because we need to provide and get information from the user. You need to add the same into InstallExecuteSequence if you want to provide quiet installation.

Custom Action 1 has to be run before the new dialog ConfigSFSDlg is created. So we will queue this action right before the standard dialog PrepareDlg. The following code put this action in the right place:

jhaug09-111small.jpg

And below is the InstallUISequence table in the result mis file:

jhaug09-11.jpg

3.6.2    In the ControlEvent Table
For Custom Action 2, I found no way to put it in the right place using the same way as the Custom Action 1. So I used another approach: the custom action will be called right after the user picks the website and click the Next button in the ConfigSFSDlg.

You can find a good sample code here regarding this approach: http://www.codeproject.com/KB/install/WIXSSRSInstaller.aspx
jhaug09-14small.jpg

3.6.3    By a Call to Session.DoAction()
Custom Action 3 is called inside the Custom Action 2 with the following code:
Session.DoAction("SetSFSInstallPath2"). SetSFSInstallPath2 is Custom Action 3's name defined in Wix.

All three approaches are well explained in Boneman's Blog here:
http://bonemanblog.blogspot.com/2005/10/custom-action-tutorial-part-i-custom.html

These are three Custom Actions in the result msi file:

jhaug09-13.jpg

4    Add a New Dialog in Wix3
In Wix2, you'll have to make changes in the Wix source code and recompile the Wix2 UI library in order to add a new customized dialog into a standard installation UI sequence. So I ended up with migrating all Wix2 code to Wix3.

Below is an extraction from WixWiKi:
"The stock Wix user interface sequences, UiExtension, do not support inserting a custom dialog. However the underlying dialogs have been carefully constructed such that the navigation logic, the back and next buttons, is not part of the dialog itself. The navigation logic is actually defined as part of the sequence itself. What this means is that you can build your own custom UI sequence using just plain old Wix."

The basic steps are:
1.    Design UI of the new dialog, e.g. ConfigSFSDlg2.wxs, in my example.
2.    Make a copy of a standard user interface, e.g. WixUI_InstallDir.wxs.
3.    Insert your new dialog into UI sequence by modifying the above WixUI_InstallDir.wxs and rename it to, e.g. WixUI_InstallDir_SFS.wxs in my example.
In Wix3, the sequence of dialog is controlled by Event Publishing of Next/Back buttons as shown below.

jhaug09-141small.jpg

Then in your main wxs file, reference your modified UI sequence wxs file as shown below:

jhaug09-15.jpg

 Jirong Hu is a software development consultant specialized in configuration management, build and release management. He has lots of experience in J2EE development with IBM Rational tools, and currently he's working on .Net application's build and packaging with Microsoft TFS and other open source tools such as CruiseControl.Net, NAnt and Wix.

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.