How to: Integrate a Topshelf Based Service With vs Setup Projects

We’ve recently started to migrate all of our Windows Services from a classic ServiceBase based approach to the hosting framework Topshelf.

Previously we used the standard ServiceInstaller / ServiceProcessInstaller tandem to integrate our services with MSI deployment. This does not work with Topshelf (since Topshelf does the service installation itself via the Registry). However it’s pretty easy to write a custom installer for that. You can do something like this:

An installer for Topshelf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class TopshelfInstaller : Installer
{
    private const string AssemblyIdentifier = "TopshelfAssembly";
    private const string InstallUtilAssemblyParameter = "assemblypath";

    public override void Install(IDictionary stateSaver)
    {
        var topshelfAssembly = Context.Parameters[InstallUtilAssemblyParameter];
        stateSaver.Add(AssemblyIdentifier, topshelfAssembly);

        RunHidden(topshelfAssembly, "/install");

        base.Install(stateSaver);
    }

    public override void Uninstall(IDictionary savedState)
    {
        var topshelfAssembly = savedState[AssemblyIdentifier].ToString();

        RunHidden(topshelfAssembly, "/uninstall");

        base.Uninstall(savedState);
    }

    private static void RunHidden(string primaryOutputAssembly, string arguments)
    {
        var startInfo = new ProcessStartInfo(primaryOutputAssembly)
        {
            WindowStyle = ProcessWindowStyle.Hidden,
            Arguments = arguments
        };

        using (var process = Process.Start(startInfo))
        {
            process.WaitForExit();
        }
    }
}

The interesting part is this line:

1
var topshelfAssembly = Context.Parameters[InstallUtilAssemblyParameter];

Took me some time to find this. During installation the Parameter Dictionary attached to the Context contains the full target filename of the assembly being installed (key is assemblypath). With this path you can directly launch the /install or /uninstall command for the Topshelf based exe.

HTH

P.S.: This resource pointed me in the right direction.

Comments