So we\'ve produced a windows service to feed data to our client application and everything is going great. The client has come up with a fun configuration request that requ
Have you tried the sc / service controller util? Type
sc create
at a command line, and it will give you the help entry. I think I've done this in the past for Subversion and used this article as a reference:
http://svn.apache.org/repos/asf/subversion/trunk/notes/windows-service.txt
Just to improve perfect answer of @chris.house.00 this, you can consider following function to read from your app settings:
public void GetServiceAndDisplayName(out string serviceNameVar, out string displayNameVar)
{
string configurationFilePath = Path.ChangeExtension(Assembly.GetExecutingAssembly().Location, "exe.config");
XmlDocument doc = new XmlDocument();
doc.Load(configurationFilePath);
XmlNode serviceName = doc.SelectSingleNode("//appSettings//add[@key='ServiceName']");
XmlNode displayName = doc.SelectSingleNode("//appSettings//add[@key='DisplayName']");
if (serviceName != null && (serviceName.Attributes != null && (serviceName.Attributes["value"] != null)))
{
serviceNameVar = serviceName.Attributes["value"].Value;
}
else
{
serviceNameVar = "Custom.Service.Name";
}
if (displayName != null && (displayName.Attributes != null && (displayName.Attributes["value"] != null)))
{
displayNameVar = displayName.Attributes["value"].Value;
}
else
{
displayNameVar = "Custom.Service.DisplayName";
}
}
sc create [servicename] binpath= [path to your exe]
This solution worked for me.
You can run multiple versions of the same service by doing the following:
1) Copy the Service executable and config to its own folder.
2) Copy Install.Exe to the service executable folder (from .net framework folder)
3) Create a config file called Install.exe.config in the service executable folder with the following contents (unique service names):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ServiceName" value="The Service Name"/>
<add key="DisplayName" value="The Service Display Name"/>
</appSettings>
</configuration>
4) Create a batch file to install the service with the following contents:
REM Install
InstallUtil.exe YourService.exe
pause
5) While your there, create an uninstall batch file
REM Uninstall
InstallUtil.exe -u YourService.exe
pause
EDIT:
Note sure if I missed something, here is the ServiceInstaller Class (adjust as required):
using System.Configuration;
namespace Made4Print
{
partial class ServiceInstaller
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
private System.ServiceProcess.ServiceInstaller FileProcessingServiceInstaller;
private System.ServiceProcess.ServiceProcessInstaller FileProcessingServiceProcessInstaller;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.FileProcessingServiceInstaller = new System.ServiceProcess.ServiceInstaller();
this.FileProcessingServiceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
//
// FileProcessingServiceInstaller
//
this.FileProcessingServiceInstaller.ServiceName = ServiceName;
this.FileProcessingServiceInstaller.DisplayName = DisplayName;
//
// FileProcessingServiceProcessInstaller
//
this.FileProcessingServiceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.FileProcessingServiceProcessInstaller.Password = null;
this.FileProcessingServiceProcessInstaller.Username = null;
//
// ServiceInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] { this.FileProcessingServiceInstaller, this.FileProcessingServiceProcessInstaller });
}
#endregion
private string ServiceName
{
get
{
return (ConfigurationManager.AppSettings["ServiceName"] == null ? "Made4PrintFileProcessingService" : ConfigurationManager.AppSettings["ServiceName"].ToString());
}
}
private string DisplayName
{
get
{
return (ConfigurationManager.AppSettings["DisplayName"] == null ? "Made4Print File Processing Service" : ConfigurationManager.AppSettings["DisplayName"].ToString());
}
}
}
}
The simplest approach is is based the service name on the dll name:
string sAssPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string sAssName = System.IO.Path.GetFileNameWithoutExtension(sAssPath);
if ((this.ServiceInstaller1.ServiceName != sAssName)) {
this.ServiceInstaller1.ServiceName = sAssName;
this.ServiceInstaller1.DisplayName = sAssName;
}
Another quick way to specify a custom value for ServiceName
and DisplayName
is using installutil
command line parameters.
In your ProjectInstaller
class override virtual methods Install(IDictionary stateSaver)
and Uninstall(IDictionary savedState)
public override void Install(System.Collections.IDictionary stateSaver)
{
GetCustomServiceName();
base.Install(stateSaver);
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
GetCustomServiceName();
base.Uninstall(savedState);
}
//Retrieve custom service name from installutil command line parameters
private void GetCustomServiceName()
{
string customServiceName = Context.Parameters["servicename"];
if (!string.IsNullOrEmpty(customServiceName))
{
serviceInstaller1.ServiceName = customServiceName;
serviceInstaller1.DisplayName = customServiceName;
}
}
Install the service with installutil
adding your custom name using /servicename
parameter:
installutil.exe /servicename="CustomServiceName" "c:\pathToService\SrvcExecutable.exe"
Please note that if you do not specify /servicename
in the command line the service will be installed with ServiceName and DisplayName values specified in ProjectInstaller properties/config