JOB REFERRALS
    ON THIS PAGE
    ARCHIVES
    CATEGORIES
    BLOGROLL
    LINKS
    SEARCH
    MY BOOKS
    DISCLAIMER
 
 Saturday, November 20, 2010
Windows Service in F#

Recently I received an email forwarded to me from a fan of the F# language, asking about the steps required to build a Windows service (the Windows equivalent to a background daemon from Unix) in F#. It’s not hard, but getting the F# bits in the right place can be tricky—the key being, the Installer (that will be invoked when installutil.exe is asked to install your service) has to have the right custom attribute in place, and the service has to have all the bits lined up perfectly. So, without further ado….

  1. Create an F# Application project
  2. Add references to “System.ServiceProcess” and “System.Configuration.Install”
  3. Create the service itself:

namespace FSService

    open System.ComponentModel
    open System.Configuration.Install
    open System.ServiceProcess

    type WindowsService() as this =
        inherit ServiceBase()

        do
            this.ServiceName <- "My Windows Service"
            this.EventLog.Log <- "Application"

        override this.OnStart(args:string[]) =
            base.OnStart(args)

        override this.OnStop() =
            base.OnStop()

        static member Main() =
            ServiceBase.Run(new WindowsService())

  1. Create the service installer class (inside the same namespace, for easy reference):

    [<RunInstaller(true)>]
    type MyInstaller() as this =
        inherit Installer()
        do
            let spi = new ServiceProcessInstaller()
            let si = new ServiceInstaller()
            spi.Account <- ServiceAccount.LocalSystem
            spi.Username <- null
            spi.Password <- null

            si.DisplayName <- "My New F# Windows Service"
            si.StartType <- ServiceStartMode.Automatic
            si.ServiceName <- "My Windows Service"

            this.Installers.Add(spi) |> ignore
            this.Installers.Add(si) |> ignore

  1. Build.
  2. Take the resulting executable, install the service by using the “installutil.exe” utility from the .NET SDK: “installutil /I FSService.exe”
  3. Verify that the service has been installed in the Services Control Panel.

MSDN documentation describes Windows services and the various overridable methods from ServiceBase, as well as how the ServiceInstaller configuration options describe the service itself (account to use, start mode, etc).

Update: Whoops! I forgot something else—the service above will install, but it won’t start! The symptom is that you’ll get a “timeout” error immediately after trying to start the service, and the reason for that is because F# (unlike C#) doesn’t recognize the Main() member as an assembly entry point. (I knew that, I swear.)

The fix is to move Main() outside of the WindowsService type and into a module (which EntryPoint requires), like so:

module Entry =
    [<EntryPoint>]
    let Main(args) =
        ServiceBase.Run(new WindowsService())
        0

Sorry about that. Bear in mind, too, that the service may have additional properties (CanShutdown, CanPauseAndContinue, etc) that you may also want to set, in order to receive those events (OnShutdown, OnPause, etc) in the service.

From here, though, things should be smooth sailing.