views:

255

answers:

4

I have written a Windows service, of which I want to have 1 instance running per customer. This is because the customers each have their own DB with identical schemas; the only difference between the Windows services is that they will each have a different parameter corresponding to the customer DB that they're designated to serve. (And I can't have one service with multiple worker threads, because the DB connection uses a static variable, which I can't fiddle with across threads.)

I found this neat little tutorial about how to make a Windows Service, but it only shows me how to set it up for a single service. I want to set up n instances of the service, each one with a display name that includes the customer name, running with the command line parameter that denotes the customer ID.

The tutorial linked above has a class called MyWindowsServiceInstaller, which installs the windows service on the local system, and I'm guessing this would be a logical place to set up a foreach loop through all my customers, setting up one service for each. But I can't see anywhere on the interfaces provided that would allow me to set up a command line parameter for the new service.

How do you do it?

+1  A: 

You basically need to install the service several times, and customise it with it's exe.config file.

Alternatively, you can have one service that runs different worker threads for each client.

Update

exe.Config is an Application Configuration File

I have no idea how to use that installer component to install several instances of the service, I wasn't aware you could.

Where we need several instances of one of our services to run on one machine, we actually only install it once, then literally copy the installed folder and change the exe name for the second instance. The second instance is then configured in it's own Application Configuration File.

Binary Worrier
In the tutorial I linked to above, there's a class called MyWindowsServiceInstaller, which does the installation work. It looks like that should be the place to set up a loop for all customers - but I can't see anywhere at all to set up the command line parameters for each service. How do you set up the parameters? and pardon my ignorance, but what is exe.config?
Shaul
have updated my question to clarify some of the points you mentioned.
Shaul
+1 for the link to the App Config File
Shaul
A: 

As far as I known it is impossible to provide startup parameters using either ServiceInstaller, ServiceProcessInstaller or installutil. However, it is possible to provide startup parameters using some COM api's from advapi.dll (check the left menu). A complete collection of the required calls can be found here. It's a class (also) called ServiceInstaller that contains the required external methods and some utility methods.

You'd want to use the utility method InstallAndStart. It accepts a service name, a display name and a path to the executable that represents your Windows service. You can call it like this:

InstallAndStart("MyService", "My Service For User 1",
                "c:\\pathtoexe\MyService.exe user1");

If you have the following service the parameter startupParam will receive the value user1.

class Program : ServiceBase
{
    private string startupParam;

    static void Main(string[] args)
    {
        string arg = args[0];
        ServiceBase.Run(new Program(arg));
    }

    public Program(string startupParam)
    {
        this.ServiceName = "MyService";
        this.startupParam = startupParam;
    }
    ...
}
Ronald Wildenberg
ummm... just tried this, and it doesn't look like installutil allows you to pass parameters...? Am I missing something?
Shaul
Hm, seems I'm not correct. Sorry for that and forget about the installutil part. I use a custom ServiceInstaller class myself that uses COM api's to start and stop services. This class allows passing parameters and I thought installutil would do the same. I'll update my answer...
Ronald Wildenberg
+2  A: 

Wil Peck wrote a good article about how to install multiple instances of a windows service on a single box. The basic idea is that you have to trick the installer into thinking they are different services by giving them different names.

Having said that, it seems like it would be easier (and more maintainable) to redesign your database connection code so that it can support multiple worker threads.

Jeff Sternal
+1 for the link, +1 again if I could for the advice to have several worker threads in one service. You can always have a GUI that remotes to the service and shows information on the running threads.
Binary Worrier
Yup, Wil has the answer. Thanks a ton for the pointer!
Shaul
A: 

If using third party tools is ok with you, try http://installer.codeeffects.com. They let you build an .exe installer for your Windows service and add parameters to the UI of the installer. Also, you don't need to develop your own setup project. Hope this helps.

Jane