Multiple instances of same windows service

There are times were you want to be able install multiple instances of the same windows service onto the same server (i.e. to support different environments but you have limited servers at your diposal) this poses a problem, you are probably aware windows will not allow more than 1 windows service to be installed with the same service name and when you create a windows service project and an installer you assign the service name at design time.

We need is someway to assign the service name at runtime, well after some extensive googling around I found a way of achieving this, the ProjectInstaller has 2 methods you can override Install and Uninstall which enables us to make changes to the service installer at the at runtime 🙂 Yeah that’s great however how do we assign the service name?! Fear not! at our disposal is the Context class that happens to have a Parameters dictionary so we can now capture custom command arguments passed to installutil.exe, enough yapping time for some code:

public override void Install(System.Collections.IDictionary stateSaver)
{
	RetrieveServiceName();
	base.Install(stateSaver);
}

public override void Uninstall(System.Collections.IDictionary savedState)
{
	RetrieveServiceName();
	base.Uninstall(savedState);
}

private void RetrieveServiceName()
{
	var serviceName = Context.Parameters["servicename"];
	if (!string.IsNullOrEmpty(serviceName))
	{
		this.SomeService.ServiceName = serviceName;
		this.SomeService.DisplayName = serviceName;
	}
}

In this instance I have made the servicename argument optional in which case it will use the default assigned at design time, you could enforce it in your version.

We can now use this like this:

installutil /servicename=”My Service [SysTest]” d:\pathToMyService\Service.exe

and for uninstall:

installutil /u /servicename=”My Service [SysTest]” d:\pathToMyService\Service.exe

Note for the uninstall you need to supply the servicename so windows how to resolve the service to uninstall

One thing that suprises me is how hidden this implementation is, most results bring up people wanting the same functionality and being told it ain’t possible and articles that suggest messing with config files this to me seems to be a much simpler and nicer way to achieve multiple instances.

Advertisements

25 thoughts on “Multiple instances of same windows service

  1. You have the line this.SomeService.ServiceName = serviceName;

    When I try to implement this, using my service name, i.e. MyService, I get that the ProjectInstaller does not contain a definiton for MyService. Is there another piece of code I need somewhere? Thanks!

  2. Chris,

    You need to change the “someService” to the ServiceInstaller name. It’s probably ServiceInstaller1 as that is the default.

    Here’s the code …

    private void RetrieveServiceName()
    {

    object serviceName = Context.Parameters(“servicename”);

    if (!string.IsNullOrEmpty(serviceName)) {
    this.ServiceInstaller1.ServiceName = serviceName;
    this.ServiceInstaller1.DisplayName = serviceName;
    }

    }
    FOL

  3. Hi,
    Your article is really worth and helpful.But there are certain issues related to it.
    Here is the requirement that I need and the problem i face during implemetation of this code..- I need to create 3 instances of the window service. The service is created for monitoring 3 different folders located in some drive(Its a folder tracing windows service to be precise). What I do is, I have copied the required files (file.exe, file.exe.config, file.installlog,file.pdp,file.vshost.exe and file.vshost.exe.config) in 3 differnt folders. I install the service as said by u using

    -installutil /servicename=”CheckFolderService[SysTest]” d:\CheckFolder1\CheckFolderService.exe

    installutil /servicename=”CheckFolderService[SysTest]” d:\CheckFolder2\CheckFolderService.exe

    installutil /servicename=”CheckFolderService[SysTest]” d:\CheckFolder3\CheckFolderService.exe

    The problem I am getting is, in service window, I see only one service, the latest one installed, that is from CheckFolder3.. and I cannot get the other 3..

    Also I need to edit the configuration files for all the three instances..
    Please help and give suggestions as soon as possible.

    Thanks.
    Niti Jotani

  4. Also, It gives me Win32Exception when i install another instance.. “The transaction has failed and rollback has perfomed..” Actually this is because the service is already installed in the machine.. So plz suggest me what can be done?

  5. @Niti,

    You need to specify different service names to differentiate each instance i.e.

    installutil /servicename=”CheckFolderService 1” d:\CheckFolder1\CheckFolderService.exe

    installutil /servicename=”CheckFolderService 2” d:\CheckFolder2\CheckFolderService.exe

    installutil /servicename=”CheckFolderService 3” d:\CheckFolder3\CheckFolderService.exe

  6. Thanks Michael. I did the same. I am able to run multiple instance of my service now.:)
    Thanks again for instant reply.

  7. From the installation perspective and different folders with different app.config will work.

    Assume Single Exe , Single App.Config and 2 Services

    installutil /servicename=”CFSService 1” d:\CFS.exe
    installutil /servicename=”CFSService 2” d:\CFS.exe

    In the custom service base class say “CFSService” in InitializeComponent Will we be able to identify the current service name?

    Reason to identify is look for different configuration data for each services?

    I looked on solution over the web
    and got a workaround “Appending the ServiceName as a commandline paramter in the execute path maybe a possbile workaround”.

    Your thoughts ?

  8. @Ilan,

    You should be able to identify the service by name using the ServiceName property from the ServiceBase class

  9. Hi i got the following error

    installUtil /servicename=”Test” D:\BGTWorkerNodeAgent.msi

    Exception occurred while initializing the installation:
    System.IO.FileLoadException: Could not load file or assembly ‘file:///D:\BGTWork
    erNodeAgent.msi’ or one of its dependencies. Data of this type is not supported.
    (Exception from HRESULT: 0x8007065E).

    My coding
    public override void Install(System.Collections.IDictionary stateSaver)
    {
    RetrieveServiceName();
    base.Install(stateSaver);
    }

    public override void Uninstall(System.Collections.IDictionary savedState)
    {
    RetrieveServiceName();
    base.Uninstall(savedState);
    }

    private void RetrieveServiceName()
    {

    var serviceName = Context.Parameters[“servicename”];
    if (!string.IsNullOrEmpty(serviceName))
    {
    this.serviceInstaller1.ServiceName = serviceName;
    this.serviceInstaller1.DisplayName = serviceName;

    }
    }

  10. You can’t use installutil against an *.msi you should run it against the .net *.exe that is built

  11. Pingback: Still creating windows services in .NET by hand? « Journal of a software dev
  12. Apart from passing service name on the fly, I want to pass few arguments to the service also.
    Like belo where 30 is the argument.
    installutil /servicename=”CFSService 1” d:\CFS.exe 30

    I’m not getting what code changes I have to make to the installer to take argument also. Can you please help me

  13. You could use this:

    var arg = Context.Parameters[“myargument”];

    Then run it like this installutil /servicename=”CFSService 1” /myargument=”30″ d:\CFS.exe but this is a bad way instead use app.config and put the setting in there instead that way if you need to change it you can change it in the config file and restart the service if you do it as above you would need to re-install the service.

  14. I tried the exact same thing and I get an error –

    Rolling back assembly ‘C:\Program Files (x86)\TestCase\Bin\AuditCMService.exe’.
    Affected parameters are:
    logtoconsole =
    servicename = TestCase.SN1
    a = 1
    assemblypath = C:\Program Files (x86)\TestCase\Bin\AuditCMService.exe
    logfile = C:\Program Files (x86)\TestCase\Bin\AuditCMService.InstallLog

    An exception occurred during the Install phase.
    System.NullReferenceException: Object reference not set to an instance of an object.

  15. As I understand, the ServiceName needs to be set in two places:
    1) On the ServiceInstaller class. The example code does this.
    2) On the ServiceBase descendant class. I think this is missing from the example code.
    I have a class MyService that extends ServiceBase. I don’t set the name on it directly, but rely on the above code which sets the ServiceName on the installer. I am able to install multiple services successfully using this code, but I find that none of the services is aware of its identity. That is, if I check the ServiceName property on MyService at runtime, I will find that it is set to empty string.

    What’s a good way to also set the ServiceName on my ServiceBase descendant instance?

Comments are closed.