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:

  1. class Program {  
  2.     static void Main() {  
  3.         if (Environment.UserInteractive) {  
  4.             ServiceManager serviceManager = new ServiceManager();  
  5.             serviceManager.OpenAll();  
  6.             Console.ReadKey();  
  7.             serviceManager.CloseAll();  
  8.         }  
  9.         else  
  10.             ServiceBase.Run(new WindowsService());  
  11.     }  
  12. }  
  13.   
  14. public class WindowsService : ServiceBase  
  15. {  
  16.     public static string WindowsServiceName = "Windows Service Name";  
  17.     public static string WindowsServiceDescription = "Windows Service Description";  
  18.     public static string WindowsServiceUsername = @".\username";  
  19.     public static string WindowsServicePassword = "password";  
  20.   
  21.     private readonly ServiceManager serviceManager = new ServiceManager();  
  22.   
  23.     private readonly IContainer components = new Container();  
  24.   
  25.     protected override void Dispose(bool disposing) {  
  26.         if (serviceManager != null) serviceManager.CloseAll();  
  27.         if (disposing && (components != null)) components.Dispose();  
  28.         base.Dispose(disposing);  
  29.     }  
  30.   
  31.     public WindowsService() {  
  32.         ServiceName = WindowsServiceName;  
  33.         CanStop = true;  
  34.     }  
  35.   
  36.     protected override void OnStart(string[] args) {  
  37.         base.OnStart(args);  
  38.         serviceManager.OpenAll();  
  39.     }  
  40.   
  41.     protected override void OnStop() {  
  42.         serviceManager.CloseAll();  
  43.         base.OnStop();  
  44.     }  
  45. }  
  46.   
  47. public class ServiceManager {  
  48.     readonly List<servicehost> serviceHosts = new List<servicehost>();  
  49.   
  50.     public void OpenAll() {  
  51.         OpenHost<service1>();  
  52.         OpenHost<service2>();  
  53.         ...  
  54.     }  
  55.   
  56.     public void CloseAll() {  
  57.         foreach (ServiceHost serviceHost in serviceHosts)  
  58.             serviceHost.Close();  
  59.     }  
  60.   
  61.     private void OpenHost<t>() {  
  62.         Type type = typeof(T);  
  63.         ServiceHost serviceHost = new ServiceHost(type);  
  64.         serviceHost.Open();  
  65.         serviceHosts.Add(serviceHost);  
  66.     }  
  67. }  
  68.   
  69. /// <remarks>  
  70. /// Enables application to be installed as a Windows Service by running InstallUtil  
  71. /// </remarks>  
  72. [RunInstaller(true)]  
  73. public class WcfServiceHostInstaller : Installer {  
  74.     public WcfServiceHostInstaller() {  
  75.         Installers.Add(new ServiceInstaller  
  76.                            {  
  77.                                StartType = ServiceStartMode.Automatic,  
  78.                                ServiceName = WindowsService.WindowsServiceName,  
  79.                                Description = WindowsService.WindowsServiceDescription  
  80.                            });  
  81.         Installers.Add(new ServiceProcessInstaller { Account = ServiceAccount.User, Username = WindowsService.WindowsServiceUsername, Password = WindowsService.WindowsServicePassword });  
  82.     }  
  83. }</t></service2></service1></servicehost></servicehost>  


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.

  1. <system.serviceModel>  
  2.   <services>  
  3.     <service behaviorConfiguration="DefaultBehavior" name="Namespace.Service1">  
  4.       <endpoint address="" binding="netTcpBinding" bindingConfiguration="TCPBindingConfig" name="TCPEndpoint" contract="Namespace.IService1" />  
  5.       <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="TcpMetaData" contract="IMetadataExchange" />  
  6.       <host>  
  7.         <baseAddresses>  
  8.           <add baseAddress="net.tcp://localhost:8001/Namespace/Service1" />  
  9.         </baseAddresses>  
  10.       </host>  
  11.     </service>  
  12.     <service behaviorConfiguration="DefaultBehavior" name="Namespace.Service2">  
  13.       <endpoint address="" binding="netTcpBinding" bindingConfiguration="TCPBindingConfig" name="TCPEndpoint" contract="Namespace.IService2" />  
  14.       <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="TcpMetaData" contract="IMetadataExchange" />  
  15.       <host>  
  16.         <baseAddresses>  
  17.           <add baseAddress="net.tcp://localhost:8002/Namespace/Service2" />  
  18.         </baseAddresses>  
  19.       </host>  
  20.     </service>  
  21.     ...  
  22.   </services>  
  23.   <bindings>  
  24.     <netTcpBinding>  
  25.       <binding name="TCPBindingConfig" maxBufferSize="5242880" maxReceivedMessageSize="5242880">  
  26.         <readerQuotas maxStringContentLength="5242880" />  
  27.         <security mode="None" />  
  28.       </binding>  
  29.     </netTcpBinding>  
  30.   </bindings>  
  31.   <behaviors>  
  32.     <serviceBehaviors>  
  33.       <behavior name="DefaultBehavior">  
  34.         <serviceMetadata httpGetEnabled="false" />  
  35.         <serviceDebug includeExceptionDetailInFaults="true" />  
  36.         <serviceThrottling maxConcurrentCalls="21" maxConcurrentSessions="50" />  
  37.       </behavior>  
  38.     </serviceBehaviors>  
  39.   </behaviors>  
  40. </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:

  1. /// <summary>  
  2. /// Shuffles the specified list (Extension Method for any IList<T>).  
  3. /// </summary>  
  4. /// <remarks>  
  5. /// Algorithm described at: http://en.wikipedia.org/wiki/Fisher-Yates_shuffle  
  6. /// </remarks>  
  7. /// <example>list.Shuffle();</example>  
  8. public static void Shuffle<T>(this IList<T> list)  
  9. {  
  10.     Random rng = new Random();  
  11.     int n = list.Count;  
  12.     while (n > 1) {  
  13.         n--;  
  14.         int k = rng.Next(n + 1);  
  15.         T value = list[k];  
  16.         list[k] = list[n];  
  17.         list[n] = value;  
  18.     }  
  19. }