Ok, I certainly love F# but templates are lacking out of the gate for some types of apps with one example being a Windows Service. Now, I saw a few out there folks have made but they actually make the same mistake IMO as seen in the C# windows service.
When it comes down to it, during debugging, I would prefer to have my Window Service actually run as a Console App when I am debugging and only as a true windows service when it is getting the final finishing touches.
See the code below, and note the last two public methods, “InteractiveStart” and “InteractiveStop”.
type AppHost() as this =
inherit ServiceBase()
do
this.ServiceName <- "Some Cool F# Service"
this.EventLog.Log <- "Application"
override this.OnStart(args:String[]) =
Console.WriteLine("It is working! Yeah!")
base.OnStart(args)
override this.OnStop() =
base.OnStop()
member this.InteractiveStart(args:String[]) =
this.OnStart(args)
member this.InteractiveStop() =
this.OnStop()
Next, let’s be sure to add an installer class so when we do want to run this as a true windows service, it is ready to go.
[<RunInstaller(true)>]
type MyInstaller() as this =
inherit Installer()
do
let spi = new ServiceProcessInstaller()
let si = new ServiceInstaller()
spi.Account <- ServiceAccount.NetworkService
si.DisplayName <- "Computing Service"
si.StartType <- ServiceStartMode.Automatic
si.ServiceName <- "Computing Service"
this.Installers.Add(spi) |> ignore
this.Installers.Add(si) |> ignore
Now we will layout the entry point portion of the program. This code will decide if the app should be started as a console app (InteractiveStart) by looking at the Environment.UserInteractive property. If this is true, then it is intended to be run as a console app as opposed to a windows service. YOu can see below, very simple, and makes life a lot easier during debugging early on. I use this same technique in C# as well and works great.
open System
open System.ServiceProcess
module PROGRAM =
[<EntryPoint>]
let Main(args:String[]) =
let host = new AppHost()
if Environment.UserInteractive then
host.InteractiveStart(args)
Console.ReadLine() |> ignore
host.InteractiveStop()
0
else
ServiceBase.Run(host)
0