Deano
Deano

Reputation: 1760

Debugging C# Custom Installer Classes

I have written an installation class that extends Installer and overrides afterInstall, but I'm getting a null pointer exception. How can I go about debugging my class?

Upvotes: 28

Views: 31771

Answers (14)

BenSabry
BenSabry

Reputation: 503

This is what actually worked for me.

System.Diagnostics.Debugger.Launch();

Then right click on the Installer Project and press "Install"

Upvotes: 3

Sriwantha Attanayake
Sriwantha Attanayake

Reputation: 7888

None of above worked for me. This is what actually worked. Note that you need to put insert "both" lines.

using System.Diagnostics;

MessageBox.Show("Test is about to begin");
Debugger.Launch();

Upvotes: 2

Peter
Peter

Reputation: 356

You might automate debugging of installer projects by adding following section to either .csproj or .csproj.user file:

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
  <StartAction>Program</StartAction>
  <StartProgram>$(MSBuildBinPath)\installutil.exe</StartProgram>
  <StartArguments>$(AssemblyName).dll</StartArguments>
</PropertyGroup>

Use project file if you want other developers benefit from this change and .user file if you want to use it by yourself.

Upvotes: 0

Adith
Adith

Reputation: 177

Write the following code in the beginning of the method that you want to debug

#if DEBUG
MessageBox.Show(Process.GetCurrentProcess().Id.ToString());
#endif

So when your method is called, the above code will be hit and you can then attach the debugger to the process(ctrl+alt+p) using the above process ID. You may have to start VS with elevated permissions.

Upvotes: 1

Muhammad Mubashir
Muhammad Mubashir

Reputation: 1657

In your installer method add Debugger.Launch() statement which will launch "Visual Studio just in time debugger" where you can attach an instance of visual studio and debug your installer class (MSI). This should work in Visual Studio 2010 as well. But you need to have administrative rights to do this. If you don't have administrative rights, you might have issues. So, log in as administrator for debugging MSI. For example:

public override void Install(System.Collections.IDictionary stateSaver)
{
    Debugger.Launch();
    base.Install(stateSaver);

}

In visual studio 2005, even Debugger.Break() use to work but somehow this does not work with Visual Studio 2010.

Upvotes: 4

Bob Denny
Bob Denny

Reputation: 1303

Surprised no one has actually answered. Put a MessageBox.Show("hello") into your custom action's Install() member. Build the deployment in debug config. Install. When the MessageBox appears, go into VS IDE, Debug, Attach Process and look for the instance of msiexec that is labeled "Managed". Attach the debugger to that instance of msiexec. Now go back to the source of your custom action and place a breakpoint right after the call to MessageBox.Show(). Close the MessageBox and your breakpoint will be hit, and you're debugging in the IDE!

Upvotes: 10

Almund
Almund

Reputation: 6216

For logging purposes (in 3.5) what about using:

Context.LogMessage("My message");

Upvotes: 1

Wayne Bloss
Wayne Bloss

Reputation: 5550

I use the following class to write a simple log into the target directory. In my opinion, it's easier than trying to use the Visual Studio debugger.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MyCompany.Deployment
{
    /// <summary>
    /// Enables a quick and easy method of debugging custom actions.
    /// </summary>
    class LogFile
    {
        const string FileName = "MyCompany.Deployment.log";
        readonly string _filePath;

        public LogFile(string primaryOutputPath)
        {
            var dir = Path.GetDirectoryName(primaryOutputPath);
            _filePath = Path.Combine(dir, FileName);
        }

        public void Print(Exception ex)
        {
            File.AppendAllText(_filePath, "Error: " + ex.Message + Environment.NewLine +
                    "Stack Trace: " + Environment.NewLine + ex.StackTrace + Environment.NewLine);
        }

        public void Print(string format, params object[] args)
        {
            var text = String.Format(format, args) + Environment.NewLine;

            File.AppendAllText(_filePath, text);
        }

        public void PrintLine() { Print(""); }
    }
}

Upvotes: 1

Mario Topf
Mario Topf

Reputation: 1

You can also use the installUtil.exe utility to test your installer component.

In case you created a c# class assembly with your Installer class, Change your debug settings to start the external program 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe' and enter your commandline arguments accordingly (e.g. /Args=myargument "path to the assembly")

As last set your breakpoints, press f5 and you're set to debug your code. --paralax

Upvotes: 0

stephbu
stephbu

Reputation: 5082

Something that is handy for hard to debug sections of code is

System.Diagnostics.Debugger.Break()

Will throw a breakpoint caught by any installed debugger (VStudio, WinDbg, Remote debugger etc...).

Use it to debug really tricky areas where regular F5+Go or "Attach to Process" is difficult or impossible to perform, some examples include:

  • short-lived processes
  • time-sensitive processes
  • breaking into spawned sub-processes
  • installers
  • service stop/start
  • distributed systems

Upvotes: 45

Timex
Timex

Reputation: 121

The best way I've found is to write a unit test, and new up and initialize your installer class from your unit test:

[TestClass] public class InstallerTest {
[TestMethod]
public void InstallTest() {
  // substitute with your installer component here
  DataWarehouseInstall installer = new DataWarehouseInstall();

  string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

  string installLogFilePath = Path.Combine(assemblyDirectory, "install.log");
  installer.Context = new System.Configuration.Install.InstallContext(installLogFilePath, null);      

  // Refactor to set any parameters for your installer here
  installer.Context.Parameters.Add("Server", ".");
  //installer.Context.Parameters.Add("User", "");
  //installer.Context.Parameters.Add("Password", "");
  installer.Context.Parameters.Add("DatabaseName", "MyDatabaseInstallMsiTest");
  //installer.Context.Parameters.Add("DatabasePath", "");

  // Our test isn't injecting any save state so we give a default instance for the stateSaver
  installer.Install(new Hashtable());
} }

At least then it takes advantage of the IDE tooling better. This is especially helpful for very large installers with LOTS of components. Then you can also create ordered unit tests and run them in sequence to mimic your installer during debug or your automated builds.

Another tip would be general SOLID/GRASS software principles...develop in neat/thin layers, keeping your actual "custom action" installer logic very simple and instead call into any reusable API stuff you have that is specific to your installer(s), just as we are used to with UI development. (The installer is just another UI anyway.) This is especially key if your goal is to have a certain UI experience shared across all installers of your products.

Upvotes: 10

Thomas
Thomas

Reputation:

I use EventLog.WriteEntry("source", "message"), and check the EventLog when installing. Maybe not optimal, but works for me :)

Upvotes: 1

Oscar Cabrero
Oscar Cabrero

Reputation: 4169

attach the installer process to Visual studio in Debug->Processes->Attach or CTRL + ALT + P set the breakpoint and you should be able to go

Upvotes: 4

BCS
BCS

Reputation: 78516

build a VM, install Visual studio, make a copy of it (or create a differencing Virtual HDD) and run the installer under the debugger under the VM.

That is what I would do (but I'm no expert).

Upvotes: 0

Related Questions