Creating a Setup Project for a Windows (WCF) Service with Visual Studio

Visual Studio provides a ‘Setup Project’ template for creating installers to deploy your applications. For your basic requirements, this can be a fairly straight-forward process. But if you’re looking for anything more advanced, you have to be prepared to dig into some of Visual Studio’s menus, where there’s a surprising amount of available features. It took me a bit of digging to uncover the process for creating installers for a Windows Service.

A setup project for a Windows service differs slightly from a normal installer because you want to make sure to register the service with Windows once it has been installed. This article will guide you through the step-by-step process of achieving this, as well as covering a few more advanced features of setup projects. We’ll also take a quick look at the steps involved in creating a WCF service and client.

Note that this article is aimed at Visual Studio 2008. Things will change in Visual Studio 2010 – see What’s New in Deployment.

Setting up a Windows Service Project

Let’s start from scratch and setup a very basic Windows service project. You may already have your service working, in which case you can skip this section.

Start a new Visual Studio project. Select the ‘Windows Service’ template from under the ‘Visual C#’ » ‘Windows’ section. Call it ‘HelloService’ and click ‘OK’.

new-windows-service-project

You should have a project with a ‘Service1.cs’ file. Rename the file (and class) to just ‘Service.cs’. You should also change the ‘ServiceName’ property. This can be done by double-clicking ‘Service.cs’ to load the design view. Ensure that the properties window is visible (‘View’ » ‘Properties Window’), click somewhere inside the design view to select it, and then change the ‘ServiceName’ in the properties window. This is the name by which the operating system will identify the service, so something like ‘Hello Service’ will be appropriate for now.

Implementing a Basic WCF Service

We’ll put together a very simple WCF service – borrowing heavily from Dennis van der Stelt’s example.

First we need to add references to the required WCF assemblies. To do this, right-click on ‘References’ in the solution explorer, and select ‘Add Reference…’. Under the ‘.NET’ tab, select ‘System.ServiceModel’ and then click ‘OK’.

Create a class called ‘HelloService’ (right-click on the ‘HelloService’ project and select ‘Add’ » ‘Class…’), which will act as our service contract:

using System.ServiceModel;
 
[ServiceContract]
public class HelloService
{
    [OperationContract]
    public string HelloWorld(string name)
    {
        return string.Format("Hello, {0}!", name);
    }
}

Note that usually we’d define the service contract as an interface, and have a separate implementation, but Dennis’ example provides a good starting point.

Now we need to put together some code to start up the service:

using System;
using System.ServiceProcess;
using System.ServiceModel;
using System.ServiceModel.Description;
 
public partial class Service : ServiceBase
{
    private ServiceHost host;
 
    public Service()
    {
       InitializeComponent();
    }
 
    protected override void OnStart(string[] args)
    {
        var serviceType = typeof(HelloService);
 
        var uri = new Uri("http://localhost:8080/");
        host = new ServiceHost(serviceType, new[] { uri });
 
        var behaviour = new ServiceMetadataBehavior() { HttpGetEnabled = true };
        host.Description.Behaviors.Add(behaviour);
 
        host.AddServiceEndpoint(serviceType, new BasicHttpBinding(), "Hello");
        host.AddServiceEndpoint(typeof(IMetadataExchange), new BasicHttpBinding(), "mex");
 
        host.Open();
    }
 
    protected override void OnStop()
    {
        host.Close();
    }
}

The First Sneaky Bit

I don’t think this bit is very intuitive. You need to create an ‘installer’ for the service. Note that this is different to the setup project that we will be creating shortly. To create the installer, double-click on ‘Service.cs’ in the solution explorer to open the design view. Then right-click somewhere in the design area and select ‘Add Installer’ from the menu. This should create ‘ProjectInstaller.cs’ for you.

add-installer-menu

The ‘ProjectInstaller’ design view should now be visible, and there should be two components visible: ‘serviceProcessInstaller1′ and ‘serviceInstaller1′. Ensure that the properties window is visible and select ‘serviceInstaller1′. At this point you should specify the ‘DisplayName’ and ‘Description’ of the service. These will appear in the Windows Services management interface.

service-installer-properties

Creating the Setup Project

Next, we will create the setup project. To kick things off, right-click on the solution in the solution explorer. Select ‘Add’ » ‘New Project’, then select ‘Setup Project’ from the ‘Other Project Types’ » ‘Setup and Deployment’ section. Name the project ‘HelloServiceSetup’, and click ‘OK’.

new-setup-project

Before we add the ‘HelloService’ project to the setup project, take some time to fill out the properties for the setup project. (Ensure the properties window is visible, and select the ‘HelloServiceSetup’ project in the solution explorer.) The ‘Author’, ‘Description’, ‘Manufacturer’ and ‘Title’ should be filled out.

Now we need to add ‘HelloService’ to the setup. Right-click on ‘HelloServiceSetup’ and select ‘Add’ » ‘Project Output…’. Make sure the ‘HelloService’ project is selected and select ‘Primary output’. You can choose whether you want to install the debug output or the release output, or just whatever is the active configuration. It probably makes sense to select the release option, but it depends what you want to be installing. Click ‘OK’ and you should see ‘Primary output from HelloService’ appear, as well as ‘Microsoft .NET Framework’ as a detected dependencies.

primary-output

The Other Sneaky Bit

Now, the other non-intuitive bit. Even though we have an installer associated with the service project, the setup project doesn’t pick this up automatically. We have to define custom actions for the setup project. There are a few ways to get to the custom actions editor. Here’s one of them: right-click on ‘HelloServiceSetup’ and select ‘View’ » ‘Custom Actions’. Then, right-click on ‘Custom Actions’ in the editor and select ‘Add Custom Action…’. In the pop-up dialog, double-click ‘Application Folder’, select ‘Primary output from HelloService’ and click ‘OK’. This should add ‘Primary output from HelloService’ to each of the four custom actions.

custom-actions

At this point, the service and associated setup project should be working. Let’s try it out. Change the configuration type to ‘Release’ if that’s the project output you’ve selected, and then build the whole solution (‘Build’ » ‘Build Solution’, or just hit F6). Note that by default this doesn’t build the setup projects (you can change this option in the ‘Configuration Manager’), so once that has finished, right-click on ‘HelloServiceSetup’ and click ‘Build’.

Now the setup program is ready to be run. You can run it straight from the filesystem (hunt around in the ‘Release’ directory for ‘HelloServiceSetup’), or just right-click on HelloServiceSetup and select ‘Install’.

install-menu

You should be able to run through the installation process. At the end of the process, you should have to fill out the ‘Set Service Login’ dialog. (If the install seems to have stalled, you may have to hunt around for this dialog – it has a habit of appearing behind other windows.) You can just use your Windows user account here (but make sure to include the domain).

set-service-login

Testing Your Service

If you’d like to try out the service, you can create a new project. Right click on the solution in the solution explorer, select ‘Add’ » ‘New project…’. Select ‘Console Application’ from the ‘Windows’ section. Name the project something like ‘HelloClient’ and hit ‘OK’.

Visual Studio provides a built-in way of adding service references, which should make this next step relatively painless. You need to make sure the WCF service is running first. Since we’ve installed the service, you should be able to start it from the Services manager. (The Services manager can be accessed in a number of ways – one of which is from under ‘Administrative Tools’ in the Control Panel.) Locate your service in the list of services. It should be identified by the ‘DisplayName’ you gave it. Right-click on the service and select ‘Start’. The service should now be listed as ‘Started’.

services-manager

All being well, you can now switch back to Visual Studio. Right-click ‘HelloClient’ in the solution explorer and select ‘Add Service Reference…’. In the address box, enter ‘http://localhost:8080/’ and click ‘Go’. After a little while, ‘HelloService’ should appear in the ‘Services’ box. In the ‘Namespace’ box, enter something like ‘HelloServiceReference’, and click ‘OK’. This service reference should now appear in your project.

add-service-reference

Time to write some code:

using System;
 
public class Program
{
    public static void Main(string[] args)
    {
        var proxy = new HelloServiceReference.HelloServiceClient();
        var result = proxy.HelloWorld("world");
        Console.WriteLine("Result: " + result);
        Console.ReadKey();
    }
}

Now try it out. Right-click on ‘MyClient’ in the solution explorer, and select ‘Debug’ » ‘Start new instance’. A console window should appear like the one below:

hello-world

Uninstalling

You can uninstall the service using the Control Panel, or by simply right-clicking on the setup project in Visual Studio and selecting ‘Uninstall’.

Customising the Setup Project

You may wish to customise the setup process. I’ll guide you through a couple of things you might want to try out.

Aesthetics

An installer will look a lot more polished if you’ve got your company logo on it. First, you need to put together an image. The image should be about 500×70 pixels, and must be a .bmp or .jpg file.

Once you have the image, you should locate the HelloServiceSetup project’s directory on the filesystem (something like: ‘…\Projects\HelloService\HelloServiceSetup’) and copy your image into that directory. Then, back inside Visual Studio, right-click on the ‘HelloServiceSetup’ project and select ‘Add’ » ‘File…’. Browse to the project’s directory and select the image you just copied there. You should see the file appear in the solution explorer.

To now associate the image with the setup process, right-click on ‘HelloServiceSetup’ and select ‘View’ » ‘User Interface’. This should display a tree of the various installation steps. Select each leaf in the tree in turn, and specify the BannerBitmap property in the properties window. In the drop-down, select ‘(Browse…)’, then double-click ‘Application Folder’ and select the image. Don’t forget to repeat this step for each stage of the installation.

Custom Actions

To get our service to install, we had to setup some custom actions. You can take these further, and have some code executed when installing or uninstalling. For example, if your application generates log files during use, you should clear these during the uninstall process.

Right-click on ‘ProjectInstaller.cs’ in the solution explorer (in the service project), and select ‘View Code’. Then we need to override the ‘Uninstall’ method. See below:

namespace HelloService
{
    using System;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Collections;
 
    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }
 
        public override void Uninstall(IDictionary savedState)
        {
            try
            {
                // Your code here
            }
            catch (Exception)
            {
            }
 
            base.Uninstall(savedState);
        }
    }
}

You can fill in your own code as necessary. But make note of the fact that we’re surrounding the code with a try-catch block. If you don’t catch an exception that gets thrown, the uninstaller will abort and it becomes very difficult to uninstall the application. (If you do get stuck here, you may benefit from a utility from Microsoft called ‘Msizap.exe’ – but beware.)

The following code may be useful for deleting log files, if your application generates them:

private static void DeleteLogFiles()
{
    var installDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
 
    var logFiles = Directory.GetFiles(installDir, "*.log*");
    foreach (var logFile in logFiles)
    {
        File.Delete(logFile);
    }
}

Download

I’ve zipped up the Visual Studio solution in case you’d like to take a look at it.

This entry was posted in .NET, C#. Bookmark the permalink.

3 Responses to Creating a Setup Project for a Windows (WCF) Service with Visual Studio

  1. Pingback: lyjodiwet

  2. Pingback: zewetokatoguk

  3. Pingback: yjefubono