How to install a windows service programmatically

B

Bodo

Hi,
I'm trying to build my own class that inherits from
System.Configuration.Install.Installer to build my own functionality of
installing a windows service.
However I'm struggeling with the install method:

public virtual void Install( IDictionary stateSaver);

I can't find any clues on how to specify stateSaver when calling
Install(stateSaver) method.

Also I' missing any class properties to state the path and name of the
application to run as a service.

Has anyone managed successfully to build his own custom class that
registeres a windows service with c# using .net framework?

TIA
Bodo
 
J

Jeroen Mostert

Bodo said:
I'm trying to build my own class that inherits from
System.Configuration.Install.Installer to build my own functionality of
installing a windows service.
However I'm struggeling with the install method:

public virtual void Install( IDictionary stateSaver);

I can't find any clues on how to specify stateSaver when calling
Install(stateSaver) method.
There's no official documentation on this that I'm aware of, but I do happen
to know how this works. In any case, this part is very simple: "stateSaver"
can simply be empty initially.
Also I' missing any class properties to state the path and name of the
application to run as a service.

Has anyone managed successfully to build his own custom class that
registeres a windows service with c# using .net framework?
*raises hand*

In my case, it was a requirement that the installation parameters (service
name, display name etc.) be part of the configuration file, so a single
service could be installed multiple times under different names. (I don't
recommend this setup in general, by the way, as it can lead to an explosion
of services; a much better approach is to build one service that can handle
multiple workloads through configuration.)

Your Install() method should look somewhat like this:

public override void Install(IDictionary stateSaver) {
// There is only one service
ServiceInstaller serviceInstaller = new ServiceInstaller();
string serviceName = ConfigurationManager.AppSettings["ServiceName"];
if (string.IsNullOrEmpty(serviceName)) throw new
ConfigurationErrorsException("Missing 'ServiceName' setting in <appSettings>.");
serviceInstaller.ServiceName = serviceName;
string displayName = ConfigurationManager.AppSettings["DisplayName"];
if (displayName != null) serviceInstaller.DisplayName = displayName;
string description = ConfigurationManager.AppSettings["Description"];
if (description != null) serviceInstaller.Description = description;
Installers.Add(serviceInstaller);
base.Install(stateSaver);
}

ServiceInstaller does the heavy lifting for you. You can take the settings
from "stateSaver" instead of the configuration file. You can invent your own
keys for this -- I recommend using a prefix so you don't clash with the
settings the framework is going to be storing there.

Sample use of your project installer:

Hashtable savedState = new Hashtable();
projectInstaller.Context = new InstallContext(null, args);
projectInstaller.Context.Parameters["AssemblyPath"] =
Process.GetCurrentProcess().MainModule.FileName;
projectInstaller.Install(savedState);

The "AssemblyPath" parameter is used by ServiceInstaller to... well, you can
figure this one out, I'm sure. :)
 
B

Bodo

Jeroen Mostert said:
Bodo said:
I'm trying to build my own class that inherits from
System.Configuration.Install.Installer to build my own functionality of
installing a windows service.
However I'm struggeling with the install method:

public virtual void Install( IDictionary stateSaver);

I can't find any clues on how to specify stateSaver when calling
Install(stateSaver) method.
There's no official documentation on this that I'm aware of, but I do happen
to know how this works. In any case, this part is very simple: "stateSaver"
can simply be empty initially.
Also I' missing any class properties to state the path and name of the
application to run as a service.

Has anyone managed successfully to build his own custom class that
registeres a windows service with c# using .net framework?
*raises hand*

In my case, it was a requirement that the installation parameters (service
name, display name etc.) be part of the configuration file, so a single
service could be installed multiple times under different names. (I don't
recommend this setup in general, by the way, as it can lead to an explosion
of services; a much better approach is to build one service that can handle
multiple workloads through configuration.)

Your Install() method should look somewhat like this:

public override void Install(IDictionary stateSaver) {
// There is only one service
ServiceInstaller serviceInstaller = new ServiceInstaller();
string serviceName = ConfigurationManager.AppSettings["ServiceName"];
if (string.IsNullOrEmpty(serviceName)) throw new
ConfigurationErrorsException("Missing 'ServiceName' setting in <appSettings>.");
serviceInstaller.ServiceName = serviceName;
string displayName = ConfigurationManager.AppSettings["DisplayName"];
if (displayName != null) serviceInstaller.DisplayName = displayName;
string description = ConfigurationManager.AppSettings["Description"];
if (description != null) serviceInstaller.Description = description;
Installers.Add(serviceInstaller);
base.Install(stateSaver);
}

ServiceInstaller does the heavy lifting for you. You can take the settings
from "stateSaver" instead of the configuration file. You can invent your own
keys for this -- I recommend using a prefix so you don't clash with the
settings the framework is going to be storing there.

Sample use of your project installer:

Hashtable savedState = new Hashtable();
projectInstaller.Context = new InstallContext(null, args);
projectInstaller.Context.Parameters["AssemblyPath"] =
Process.GetCurrentProcess().MainModule.FileName;
projectInstaller.Install(savedState);

The "AssemblyPath" parameter is used by ServiceInstaller to... well, you can
figure this one out, I'm sure. :)

Hi Jeroen,
thanks for pointing me to the right direction.
Withthe use of AssemblyInstaller class I'm now able to install my assemby.
However I'm missing one point, thats the Parameters required by the assembly
Windows registry entry for that service has a "Parameters" Key.
The assembly requires some string values that are stored in the Parameters
Key.

Are there any framework methods that allows me to add the values to the
Parameters Key on installation process other than adding them by
Microsoft.Win32.RegistryKey ?

Again many thanks,
Bodo
 
J

jmostert

thanks for pointing me to the right direction.
Withthe  use of AssemblyInstaller class I'm now able to install my assemby.
However I'm missing one point, thats the Parameters required by the assembly
Windows registry entry for that service  has a "Parameters" Key.
The assembly requires some string values that are stored in the Parameters
Key.

Are there any framework methods that allows me to add the values to the
Parameters Key on installation process other than adding them by
Microsoft.Win32.RegistryKey ?
There is as far as I know no way to do this other than by directly
accessing the registry. This situation is the same in the unmanaged
world -- there's no Win32 function for this. These parameters are not
part of the service configuration itself, but of the SCM configuration
-- it will pass these parameters to StartService(). Using start
parameters for services is generally not recommended, as they offer
limited room for configuration, require a service restart to pick up
changes and will not be passed along if something calls StartService()
directly. Some services use parameters as part of the path to the
executable (where the parameter never changes and is not supposed to
be user-editable) but I haven't tested if this works with
ServiceInstaller as well.

For managed services, there is no good reason to use the service
parameters anyway -- that's what .config files are for. If you want to
use parameters to be able to run the executable both as a service and
as a regular console application, a better approach is to check
Environment.Interactive from your Main and conditionally either call
ServiceBase.Run() or Service.OnStart() directly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top