Site icon Ryadel

ASP.NET - Create MSI or setup.exe installer for any .NET Project with WiX

ASP.NET - Create MSI or setup.exe installer for any .NET Project with WiX

If you're an ASP.NET developer working with client applications using either Windows Forms (aka WinForms) projects, WPF Projects, Windows Console applications, Windows Service projects and/or any .NET Core Desktop App project (and so on), you most likely know that sooner or later you'll have to find a way to deploy your work to your end-users. Such need is usually handled by creating an installer package which would arguably have the form of either a MSI file (acronym for MicroSoft Installer) or a EXE file, just like any typical software application or tool you can download from the web. You click on it, it prompts you to accept the software license and/or EULA, then (if you accept) asks you to confirm the installation path where it will unpack the files, create the desktop/start menu shortcuts, and so on. Right? Right.

Now, the question is: how can we pull it off? In other words, what's the best way to create these installer packages for the aforementioned ASP.NET projects in order to grant our end-users a decent user-friendly "installing experience", possibly using the standard Windows Installer API?

If you're using Visual Studio, there are mostly three ways to achieve such goal:

In this post we'll learn how to use WiX, which is arguably the best option of the pack (at least in our humble ASP.NET developers opinion) for a number of reasons: it's open source, has a strong community support and easily is the most powerful and configurable setup and deployment framework available.

ASP.NET - Create MSI or setup.exe installer for any .NET Project with WiX

Installation

To setup WiX in your Visual Studio environment you need to download and install the following packages, both available from wixtoolset.org, the official WiX project website:

If you have older version of Visual Studio, you can also get the extension for VS2015 down to VS2010 from this link. There's also a VS2019 Preview Extension that mostly works on Visual Studio 2019.

The installment process is quite straightforward, you'll just have to hit Next and OK a couple times to get it done: don't forget to reboot Visual Studio once the installation is done, to ensure that both the extension and the project templates will be loaded.

Creating a Sample Project

For the sake of simplicity, let's pretend you already have a WPF project ready to be deployed to the end-users called MyWFPProject, which you want pack into a MSI file. Right-click to the solution name in the Solution Explorer panel and choose Add... > New Project.

From the project template list, choose the Setup Project for WiX v3 project template:

NOTE: WiX v4 is still in beta at the time of writing, that's why we don't use it (yet).

As we can see, we called the setup project MyWPFProject_Setup: once done, you'll have a brand new WiX project containing a single Product.wxs file, which is the WiX configuration file. If you open it, you'll get a graps of how WiX works... it basically has its very own scripted XML file, which you can use to tell it what to do.

The default template that is generated when you create a new WiX project will generates a build warning. If you try to build it without performing any change, the Output window will most likely show the following warning:

The cabinet 'MySetup.cab' does not contain any files. If this installation contains no files, this warning can likely be safely ignored. Otherwise, please add files to the cabinet or remove it.

This error message is telling us that the WiX project does not yet reference an application, therefore there is nothing to install: once we add at least a single file to the installer, this warning will go away.

Minimal Configuration

Here's the minimal configuration to generate a working MSI file:

As we can see, the XML structure is quite understandable: we do have a <Product> element, containing the general info about the project we want to deploy, and a couple <Fragment> elements: the first one containing the directory info (which folder to create on the end-users machine), and the latter containing the product components, i.e. the files to copy.

It's worth noting that the <Product> element contains a <Feature> element referencing the ID of a ComponentGroup specified later on: we'll talk about this in a while.

We also removed the TODO comments and replaced them with our actual content: notice how we used $(var.MyWPFProject.TargetPath) instead of a full path. That's one of the many project reference variables, which is one of the most useful features of WiX: think of them as environment variables that you can use within the XML configuration file instead of specifying static literal values. Here's the full list of the available variables: needless to say, we used the one that references our project's main executable file - the one that is built whenever we issue the Build Visual Studio command. This sample XML configuration file will package that newly-built executable within a convenient MSI file, which we can send to our end-users for a one-click install.

That's great, right? Well, not yet! Such MSI file would still have the following major flaws:

  • No icon (argh!) - the MSI will have the ugly "nameless app" default icon, which is something we would really like to change.
  • Forced installation path - The end-user won't have the chance to select a custom installation folder: our application will be forcefully installed on C:\Program Files\MyWPFProject\.
  • No EULA - The end-user won't have the chance to read and (be forced to) accept our software's EULA before installing and using it.
  • No DLLs or external files/components - In the (most likely) scenario we have some third-party DLLs not included in the .NET Framework used, they won't be shipped, which basically means that our app will utterly crash as soon as they will be called by the compiled code: the same goes for external files and/or folders, such as: icons, images, resource files, and so on.

In the following paragraphs we'll briefly deal with these 3 critical aspects, leaving all the rest to the WiX official documentation and the WiX v3 Manual - which we strongly suggest to look at.

Application Icon

Let's start with the easy task: add a icon.ico file to the Setup project containing your favourite image(s) and then link it to the <Product> element within the XML configuration file in the following way:

As we can see, we added two elements: the <Icon> element, which contains the icon.ico file full path, and a <Property> element defining the ARPPRODUCTICON value, which specifies the foreign key to the Icon table, which is the primary icon for the Windows Installer package  (for more info about the ARPPRODUCTICON property, read here).

Custom Installation Path

Giving the end-user the chance to choose a custom installation path requires to use a WiX GUI sequence, which is basically a pre-made GUI wizard containing some additional "steps" which we can configure using pre-defined variables. This part is rather obscure in the official WiX documentation and it's one of the main reasons that drove us into writing this tutorial.

Here's how we can use the WixUI_InstallDir sequence to give our end-users the chance to replace the default installation folder with their own path:

Again, all the action happens within the <Product> element. As we can see, we added the <UIRef> element (pointing to the WixUI_InstallDir GUI sequence) and another <Property> element: the former element will empower the setup wizard with a "Choose folder..." page, while the latter will setup the default install folder that will appear - and that will be used if the user doesn't want to change it.

IMPORTANT: using a pre-made GUI sequence will require to add a Project Reference to the  WixUIExtension.dll file: to do that, right-click the References project folder, choose Add Reference from the contextual menu, then navigate to C:\Program Files (x86)\WiX Toolset v3.11\bin\ and select the WixUIExtension.dll file.

Adding the EULA

Now that we added the WixUI_InstallDir GUI sequence, adding our very own License Agreement file is rather simple. We just have to add the following elements to the <Product> element:

The <WixVariable> element mentions a LicenseAgreement.rtf file, which we'll have to add to our Setup project (right-click > Add new). If we do that, our very own EULA will be shown to our end-users during the installation phase, forcing them to either accept it or decline the whole setup process.

Adding external DLL files

Adding external DLL files will require slightly more work, as we'll have to mention each one of them individually within a brand new <ComponentGroup> element within the <Fragment> containing the files to put into the MSI package:

Needless to say, replace the sample names DLLName_01 and DLLName_01.dll (and so on) with the name & filename of your own DLLs.  As we can see, since we specified the Source attribute using the $(var.MyWPFProject.TargetDir) WiX variable, we won't have to add the full path to the DLLs... as long as they will be copied to the "build" target folder.

Once done, we'll just have to add a reference to the new ComponentGroup to the <Feature> node present in the <Product> element:

Conclusion

That's it, at least for now: if you want to look we strongly suggest to take a look at Stefan Kruger's installsite.org website, a peculiar website dedicated to the installer topic which offers valuable insights, software reviews and other useful resources for Setup Developers.

Here are other useful resources taken to this StackOverflow thread by Stein Asmul, which also contains a list of other non-WiX installer resources:

 

Exit mobile version