Friday 21 August 2009

Hosting multiple WCF Services under a single Windows Service

I am often asked how to host multiple services under a single windows service and through trial and error have been streamlining this process for clients.

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 List serviceHosts = 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>

Monday 10 August 2009

Shuffle: an extension method of random uselessfulness

UPDATE: I have updated this method here: http://thegrenade.blogspot.com/2010/02/when-random-is-too-consistent.html

Have you ever needed to randomly sort a list in C#? Add this to your nifty extensions library:

/// <summary>
/// Shuffles the specified list (Extension Method for any IList<T>).
/// </summary>
/// <remarks>
/// Algorithm described at: http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
/// </remarks>
/// <example>list.Shuffle();</example>
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}