F# Windows Application Template for Windows Service
Recently I created a posting outlining a project template for a WinForms application. This posting outlines a new project template that provides the elements for the creation windows service in F#. The template can be found on the Visual Studio Gallery:
https://visualstudiogallery.msdn.microsoft.com/1f2ee1da-e87f-4863-b98e-d8b7b63d2253
When the template is installed you get the following template added to your F# folder when creating a new F# project:
This template provides several projects elements:
- A MyService.fs and Program.fs source file providing the service elements
- An Installer.fs source file enabling the service to be installed using the installutil tool
- A command file for installing and un-installing the service
The MyService.fs source file provides the implementation of the service. The template code provides the structure for the OnStart and OnStop methods and shows how an EventLog can be created and referenced:
namespace FSharp.Service
open System;
open System.Diagnostics;
open System.Linq;
open System.ServiceProcess;
open System.Text;
type public MyService() as service =
inherit ServiceBase()
// TODO define your service variables
let eventLog = new EventLog();
// TODO initialize your service
let initService =
service.ServiceName <- "FSharp.Service"
// Define the Event Log
let eventSource = "FSharp.Service"
if not (EventLog.SourceExists(eventSource)) then
EventLog.CreateEventSource(eventSource, "Application");
eventLog.Source <- eventSource;
eventLog.Log <- "Application";
do
initService
// TODO define your service operations
override service.OnStart(args:string[]) =
base.OnStart(args)
eventLog.WriteEntry("Service Started")
override service.OnStop() =
base.OnStop()
eventLog.WriteEntry("Service Ended")
The entry point for the program is defined in the Program.fs source file:
namespace FSharp.Service
open System
open System.Collections.Generic
open System.Linq
open System.ServiceProcess
open System.Text
module Program =
[<EntryPoint>]
let Main(args) =
// Define your services
let myService = new MyService()
// Start the services
let servicesToRun = [| myService :> ServiceBase |]
ServiceBase.Run(servicesToRun)
// main entry point return
0
As you can see for a service the entry point is defined using the [<EntryPoint>] attribute.
Finally, so that the installutil tool correctly installs the service, an Installer class is also defined:
namespace FSharp.Service
open System
open System.Configuration
open System.Configuration.Install
open System.ComponentModel
open System.Linq
open System.ServiceProcess
[<RunInstaller(true)>]
type public ProjectInstaller() as installer =
inherit Installer()
let processInstaller = new ServiceProcessInstaller();
let serviceInstaller = new ServiceInstaller();
// TODO initialize your service
let initInstaller =
// Define the process settings
processInstaller.Account <- ServiceAccount.LocalSystem
processInstaller.Password <- null
processInstaller.Username <- null
// Define the service settings
serviceInstaller.Description <- "FSharp.Service MyService"
serviceInstaller.ServiceName <- "FSharp.Service.MyService"
serviceInstaller.StartType <- ServiceStartMode.Manual;
// Define the installers
let installers = [| processInstaller :> Installer; serviceInstaller :> Installer|]
installer.Installers.AddRange(installers)
do
initInstaller
The template version installs the service using the Local System account. However, this can easily be changed.
Finally, the template creates a command file that can be used to install and un-install the service. When running this command file you will need a command prompt running with elevated privileges.
Once again, hopefully you will find this template useful.
Written by Carl Nolan