Writing a Service in F #

I came back again, this time with a question about writing a service in F #. I cannot install the service using installutil. This gives me the following error.

$ installutil atfwindowsservice.exe Microsoft (R) .NET Framework Installation utility Version 4.0.30319.18408 Copyright (C) Microsoft Corporation. All rights reserved. Running a transacted installation. Beginning the Install phase of the installation. See the contents of the log file for the C:\Dev\ATF\output\bin\Debug\atfwindowsservice.exe assembly progress. The file is located at C:\Dev\ATF\output\bin\Debug\atfwindowsservice.InstallLog. Installing assembly 'C:\Dev\ATF\output\bin\Debug\atfwindowsservice.exe'. Affected parameters are: logtoconsole = logfile = C:\Dev\ATF\output\bin\Debug\atfwindowsservice.InstallLog assemblypath = C:\Dev\ATF\output\bin\Debug\atfwindowsservice.exe No public installers with the RunInstallerAttribute.Yes attribute could be found in the C:\Dev\ATF\output\bin\Debug\atfwindowsservice.exe assembly. 

The code is below. Any help is appreciated and thanks in advance.

Ramesh

 namespace service open System.ServiceProcess open System.Runtime.Remoting open System.Runtime.Remoting.Channels type atf() = inherit ServiceBase(ServiceName = "atf win service") override x.OnStart(args) = () override x.OnStop() = () 

Service code registration:

 // Learn more about F# at http://fsharp.net // See the 'F# Tutorial' project for more help.= open System open System.ComponentModel open System.Configuration.Install open System.ServiceProcess [<RunInstaller(true)>] type FSharpServiceInstaller() = inherit Installer() do // Specify properties of the hosting process new ServiceProcessInstaller(Account = ServiceAccount.LocalSystem) |> base.Installers.Add |> ignore // Specify properties of the service running inside the process new ServiceInstaller( DisplayName = "F# ATF Service", ServiceName = "atf",StartType = ServiceStartMode.Automatic ) |> base.Installers.Add |> ignore // Run the chat service when the process starts module Main = ServiceBase.Run [| new service.atf() :> ServiceBase |] 
+6
source share
3 answers

I figured out how to write a self-study service using other examples on the Internet, especially this post on the stack was useful: http://pingfu.net/programming/2011/08/11/creating-a-self-installing-windows-service- with-csharp.html

 open System open System.ServiceProcess open System.Windows open System.Threading open System.Windows.Forms open System.ComponentModel open System.Configuration.Install open System.Reflection open Microsoft.Win32 type ATFServiceInstaller() = inherit Installer() let spi_ = new ServiceProcessInstaller(Account = ServiceAccount.LocalSystem) let si_ = new ServiceInstaller( DisplayName = "ATF Service", Description="ATF service", ServiceName = "atf",StartType = ServiceStartMode.Automatic ) let dic_ = new System.Collections.Hashtable() let SVC_SERVICE_KET = @"SYSTEM\CurrentControlSet\Services" member this.install () = base.Installers.Add(spi_) |> ignore let ret = base.Installers.Add(si_) let apath = sprintf "/assemblypath=%s" (Assembly.GetExecutingAssembly().Location) let ctx = [|apath; "/logToConsole=false"; "/showCallStack"|] this.Context <- new InstallContext("atfserviceinstall.log", ctx) base.Install(dic_) base.Commit(dic_) member this.uninstall() = base.Installers.Add(spi_) |> ignore let ret = base.Installers.Add(si_) let apath = sprintf "/assemblypath=%s" (Assembly.GetExecutingAssembly().Location) let ctx = [|apath; "/logToConsole=false"; "/showCallStack"|] this.Context <- new InstallContext("atfserviceinstall.log", ctx) base.Uninstall(null) module Main = try let args = Environment.GetCommandLineArgs() match (args |> Seq.length) with | 2 -> match (args.[1]) with | "-install" -> let installer = new ATFServiceInstaller() installer.install() installer.Dispose() | "-uninstall" -> let installer = new ATFServiceInstaller() installer.uninstall() installer.Dispose() | _ -> failwith "Unrecognized param %s" args.[0] | _ -> ServiceBase.Run [| new atfservice.ATFService() :> ServiceBase |] with | _ as ex -> MessageBox.Show(ex.ToString()) |> ignore 
+2
source

I had the same problem. In the end, I added the following code, which works well and has the added benefit of not requiring installutil.exe. The service can install / uninstall on its own by going to the correct command line option. Save all your code and add the following:

 module Program = let getInstaller() = let installer = new AssemblyInstaller(typedefof<atf>.Assembly, null); installer.UseNewContext <- true installer let installService() = let installer = getInstaller() let dic = new System.Collections.Hashtable() installer.Install(dic) installer.Commit(dic) let uninstallService() = let installer = getInstaller() let dic = new System.Collections.Hashtable() installer.Uninstall(dic) [<EntryPoint>] let main (args:string[]) = match (args |> Seq.length) with |1 -> match (args.[0]) with |"-install" -> installService() |"-uninstall" -> uninstallService() |_-> failwith "Unrecognized param %s" args.[0] |_ -> ServiceBase.Run [| new atf() :> ServiceBase |] 0 

For installation, you can do the following from the command line:

 atfwindowsservice.exe -install 
+2
source

I came across this question having the same problem. I still needed to use InstallUtil.exe in the deployment and find out that the source code problem was the missing namespace in the main file.

I found this infrastructure for hosting .NET services http://topshelf-project.com/ , which greatly simplifies development and basically allows you to create a console application that you can debug, and also has a built-in Windows / Mono installer. The only drawback for me is the lack of support for installing with InstallUtil.exe again, but there is a solution for this. Instead of adding ServiceProcessInstaller and ServiceInstaller to the installers in the class inherited from Installer, override the install and uninstall methods and make them run your executable with the install / unistall parameter.

 [<RunInstaller(true)>] type public FSharpServiceInstaller() = inherit Installer() override __.Install(stateSaver : System.Collections.IDictionary) = let assemblyPath = __.Context.Parameters.["assemblypath"] stateSaver.Add(assemblyIdentifier, assemblyPath) // runProcess assemblyPath "install" base.Install(stateSaver) override __.Uninstall(savedState : System.Collections.IDictionary) = let assemblyPath = savedState.[assemblyIdentifier].ToString() // runProcess assemblyPath "uninstall" base.Uninstall(savedState) 

Full code: https://gist.github.com/jbezak/eda4cc5864059b717e71beaec47db2d9

+2
source

Source: https://habr.com/ru/post/989834/


All Articles