Deployment: Customizing your .NET deployment Projects


So you finished your application and you are ready to deploy it.  You want to create a setup for the application, but you don't want to spend a $1000+ on InstallShield or Wise InstallBuilder.  You create a setup project in Visual Studio .NET and run the setup wizard.  It creates a minimal installation, but where is my readme dialog? Where is my registration dialog?  How can I make this minimal installation actually do something besides copy my files into a directory?

The fact of the matter is that Visual Studio.NET already contains everything you need to create a rich setup experience for your users.  In this article we are going to show you  two ways to add a readme dialog to your application, the easy way and the hard way.  The easy way requires absolutely no coding.  The hard way requires coding and actually allows you to add complex custom features to your application.



 
Figure 1 - Custom ReadMe Dialog Added to the .NET Setup

Creating a Read Me Dialog the Easy Way

The first step in creating an installation for your application is to create a new Setup Project and run the Setup Wizard (See my article on creating a setup project in Visual Studio.NET).  Once you've created a minimum setup project for your application, you can use the solution explorer to add the readme dialog.  Just right click on the Setup Project and choose View->User Interface as shown in figure 2 below:

 

Figure 2 - Adding User Interfaces to your Setup Project

This menu action will bring up a template dialog with a host of additional setup dialogs you can add to your installation.  Each template is accompanied with a property sheet in which you can adjust the properties of the dialog to suit your particular dialog.  The template dialog is shown in figure 3 below. Note that the read me template is selected:

Figure 3 - The Template Dialog for adding additional Useful Screen to your set up

Double Clicking on the Read Me file adds it to the User Interface View.  We can use the Move Up and Move Down buttons to choose where it appears in our setup (see figure 4).  You can also see from the user interface screen that the setup wizard has automatically added a Welcome Screen, An Installation Folder Screen, and A Confirmation Screen.  You can click on anyone of these screens in the User Interface View and edit the properties of these views as well.  Also note that there are two installations created by the setup wizard:  a personal install sequence and an administration install sequence.  In this example we are only adding the readme to the personal install.

Figure 4 - Ordering the Readme in the User Interface Screen

By clicking on the ReadMe template in the User Interface Tree, we bring up the property screen shown in Figure 5.  The ReadMe Template has three properties:  BannerBitmap, ReadmeFile, and Sunken.  The BannerBitmap allows you to change the bitmap appearing in the upper right hand corner of the Readme dialog.  The ReadmeFile property allows you to choose a rich text format  readme file to display inside the dialog.  Rich Text Format is nice because you can display different types of fonts, formats, colors, and pictures inside the readme file.  A rich text file readme can easily be created using either Microsoft Word or if you don't own Word, you can use WordPad.

Figure 5 - Property Window for the ReadMe Dialog Template

That's all there is to creating a read me dialog using the User Interface Dialog Templates.  Now you just build your setup project in Visual Studio and run the installation it creates.  The readme that is displayed is shown in figure 6 below:

Figure 6 - Readme File Shown during Installation

Creating a Custom ReadMe File using C#

Perhaps you aren't thrilled with the ReadMe provided with the User Interface Templates.  Perhaps you want more features and enhancements to the dialog displayed. (For example, pictures don't seem to show up in the readme in the current User Interface Template).  Maybe you want a link to your website in the readme dialog so you can provide a dynamic readme update.  What can you do?  The Microsoft Visual Studio.NET framework not only supplies you with ready made custom User Interface Dialogs to add to your setup.  It also provides a way to create custom actions for your setup project.  In the custom actions you can basically add anything to your setup project that you can program yourself.  Custom actions can include doing additional file manipulation (such as copying files to other directories), GAC manipulation, Registry manipulation, Internet Updates, creating databases, etc.  The sky is the limit here, the only drawbacks art that you have to code it up (albeit, for a programmer this may not seem like drawback) and that the action will only occur at the end of your installation.

To add a custom action to your project. Right click on the deployment project in the solution explorer and choose View->Custom Actions.

Figure 7 - Choosing Custom Actions from the menu in Solution Explorer

Choosing Custom Actions, brings up the custom action screen shown in figure 8. Custom Actions can be divided into 4 categories: Install, Commit, Rollback, and Uninstall depending on what part of the installation you want to affect.  In our readme example, we add a custom action and place it in the Install section.

Figure 8 - Custom Action View in Visual Studio.NET

Creating an Custom Action Assembly

You may be wondering,  what form does a custom action take? A custom action is simply an executable, script(vb or java script), or assembly that is executed at the end of the installation.  In the case of the ReadMe Dialog, we are going to use a special Installer Class Assembly created in .NET Class Library.  The first step to creating our custom action assembly is to create a new class library project in our solution (see figure 9):

Figure 9 - Adding the class library project for the readme dialog extension

This creates a project which will contain our Installer Class.  The next step is to convert our library class to a class that uses the Installer library assembly.  First we will need to add a reference to the assembly to allow it to utilize the System.Configuration.Install library.  If we right click on the class library project and choose Add References, it will bring up the dialog shown in figure 10 and allow us to add this assembly reference to our project.

Figure 10 - Adding the Install library to our Custom Action Assembly

Note, in the case of the read me file dialog, we will also need to add System.Windows.Forms.dll reference, since the Class Library project doesn't contain it by default.

Coding the Installer

Now we are ready to code up the ReadMe Window Custom Action.  The first step is to create the derived Installer class.  Creating the Installer class will allow entry into the installation and also allow us to bring over any parameters passed from the Custom Action.  Note that we need to add an attribute RunInstaller to our Installer class and set it to true, in order to gain entry from the installation.

Listing 1 - Installer Class for the Custom Action Readme file

// Set 'RunInstaller' attribute to true.
[RunInstaller(true)]
public class ReadmeInstaller: Installer
{
public ReadmeInstaller() :base()
{
}
// Override the 'Install' method.
// The Installation will call this method to run the Custom Action
public override void Install(IDictionary savedState)
{
base.Install(savedState);
// get readme file name from custom action parameter
string ProvidedName = this.Context.Parameters["file"];
// get hyperlink to web from custom action parameters
string LinkName = this.Context.Parameters["link"];
// get the source directory of the installation from the default context parameters
string TheAssemblyPath = this.Context.Parameters["assemblypath"];
string MainDirectory = TheAssemblyPath.Substring(0, TheAssemblyPath.LastIndexOf
"\\"));
// Construct a ReadMe Dialog and pass it all the parameters from the installation ReadmeForm MyReadMe = new ReadmeForm(ProvidedName, LinkName, MainDirectory);
// Show the ReadMe Dialog in the installation
MyReadMe.ShowDialog();
}

The Readme dialog we want to create looks similar to the one in the user interface template dialog, except it also contains a field for the hyperlink to a website.  The dialog uses an rtf control to display the readme, a LinkLabel control to launch the readme Internet Explorer page, and a button to terminate the custom action.  (See Figure 11.)

Figure 11 - Readme Form Design

The rtf file is read into the control using a StreamReader.  The StreamReader reads the rtf file into a string using the file name passed in as a custom action parameter.   The string is then simply assigned to the RichTextbox control's Rtf property as shown in Listing 2.

Listing 2 - Reading the rtf file into the Readme Dialog:

void ReadRtfReadMe()
{
// Use StreamReader to read the rtf file into a string and assign it to the Rtf property of the RichTextBox
// control
StreamReader sr = new StreamReader(MainDirectoryPath + "\\" +
eadmeFileName);
richTextBox1.Rtf = sr.ReadToEnd();
sr.Close();
}

The hyperlink is activated in the LinkLabel's click event.  The program uses the Process class to launch Internet Explorer with the hyperlink passed in as a Custom Action Parameter:

Listing 3 - Launching the link from the Custom Action Data

// Put user code to initialize the page here
private void linkLabel1_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
try
{
Process.Start("IExplore.exe", ReadmeLink);
}
catch (Exception ex)
{
MessageBox.Show("Couldn't Show Page " + ReadmeLink);
}
}
 

Adding the assembly to the Setup Project as a Custom Action

Once we've finished coding up our custom action assembly and compiling it, we need to add it to the setup project.  If we go back to our Custom Action View (shown in figure 8 above), we can right click on the Install Action folder and add the class library assembly we just created by choosing Add Custom Action.  

Figure 12 - Adding the Custom Action Assembly to the Setup Project

Now we need to setup the properties of our custom action assembly.  The Properties window allows us to specify the parameters we wish to pass into the custom action assembly.  This way we can specify the rtf file used, and the hyperlink at the bottom of the page.   Clicking on the ReadMeDialogExtension.dll inside the Custom Actions View brings up the Properties Window for this custom action assembly shown in Figure 13.  Note that InstallerClass is set to True to tell the setup that we are using the Installer Class. 

Figure 13 - Property Window for the ReadMe Custom Action Assembly

If we examine the CustomActionData properties of the Properties Window, we note that the parameters are passed in a certain format.  All parameter keys are specified as /key.  All parameter values are contained in double quotes after an equal sign.  Be sure there are no spaces surrounding the equal sign, this caused me some initial problems. Remember that the parameter /file="Space Invaders.rtf" is handled inside the Installer class (Listing 1) as

// get readme file name from custom action parameter
string ProvidedName = this.Context.Parameters["file"]; 

That's all there is to creating a Custom Action in your installation.  We can now rebuild the setup project and if we run our setup we get the dialog shown in Figure 1 coming up at the end of our installation.

Conclusion

Next time you plan on deploying your application and are curious to how you are going to implement the special actions that only your installation contains, look no further.  You can create any custom action you want using the Visual Studio framework.  This way your customers won't be disappointed when you deliver them your next killer app in .NET