I thought I'd blog an example here for reference:
class Program {
static void Main() {
if (Environment.UserInteractive) {
ServiceManager serviceManager = new ServiceManager();
serviceManager.OpenAll();
Console.ReadKey();
serviceManager.CloseAll();
}
else
ServiceBase.Run(new WindowsService());
}
}
public class WindowsService : ServiceBase
{
public static string WindowsServiceName = "Windows Service Name";
public static string WindowsServiceDescription = "Windows Service Description";
public static string WindowsServiceUsername = @".\username";
public static string WindowsServicePassword = "password";
private readonly ServiceManager serviceManager = new ServiceManager();
private readonly IContainer components = new Container();
protected override void Dispose(bool disposing) {
if (serviceManager != null) serviceManager.CloseAll();
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
public WindowsService() {
ServiceName = WindowsServiceName;
CanStop = true;
}
protected override void OnStart(string[] args) {
base.OnStart(args);
serviceManager.OpenAll();
}
protected override void OnStop() {
serviceManager.CloseAll();
base.OnStop();
}
}
public class ServiceManager {
readonly ListserviceHosts = new List ();
public void OpenAll() {
OpenHost();
OpenHost();
...
}
public void CloseAll() {
foreach (ServiceHost serviceHost in serviceHosts)
serviceHost.Close();
}
private void OpenHost() {
Type type = typeof(T);
ServiceHost serviceHost = new ServiceHost(type);
serviceHost.Open();
serviceHosts.Add(serviceHost);
}
}
///
/// Enables application to be installed as a Windows Service by running InstallUtil
///
[RunInstaller(true)]
public class WcfServiceHostInstaller : Installer {
public WcfServiceHostInstaller() {
Installers.Add(new ServiceInstaller
{
StartType = ServiceStartMode.Automatic,
ServiceName = WindowsService.WindowsServiceName,
Description = WindowsService.WindowsServiceDescription
});
Installers.Add(new ServiceProcessInstaller { Account = ServiceAccount.User, Username = WindowsService.WindowsServiceUsername, Password = WindowsService.WindowsServicePassword });
}
}
And some configuration:
- Here, the binding & behaviour configuration is shared across services but you may need different configurations for different types of services.
- I use different ports for different services, but you don't have to.
<system.serviceModel>
<services>
<service behaviorConfiguration="DefaultBehavior" name="Namespace.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="TCPBindingConfig" name="TCPEndpoint" contract="Namespace.IService1" />
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="TcpMetaData" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8001/Namespace/Service1" />
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="DefaultBehavior" name="Namespace.Service2">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="TCPBindingConfig" name="TCPEndpoint" contract="Namespace.IService2" />
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="TcpMetaData" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8002/Namespace/Service2" />
</baseAddresses>
</host>
</service>
...
</services>
<bindings>
<netTcpBinding>
<binding name="TCPBindingConfig" maxBufferSize="5242880" maxReceivedMessageSize="5242880">
<readerQuotas maxStringContentLength="5242880" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentCalls="21" maxConcurrentSessions="50" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>