在F#中编写服务

时间:2015-06-26 20:45:21

标签: f#

我又回来了,这次是关于在F#写服务的问题。我似乎无法使用installutil安装该服务。它给了我以下错误。

$ 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's 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.

代码如下。任何帮助都表示赞赏,并提前感谢。

拉​​梅什

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() = ()

注册服务代码:

// 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 |]

3 个答案:

答案 0 :(得分:3)

我遇到了同样的问题。我最终添加了以下代码,它运行良好,并且具有不需要installutil.exe的额外好处。该服务可以通过传入正确的命令行参数来安装/卸载自己。保留所有代码并添加以下内容:

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

要安装,您可以从命令行执行以下操作:

atfwindowsservice.exe -install

答案 1 :(得分:3)

我想出了如何使用Web上的其他示例编写自安装服务,尤其是堆栈上的帖子非常有用: 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 :(得分:2)

我遇到同样的问题时遇到了这个问题。我仍然需要在部署中使用InstallUtil.exe,并发现原始代码的问题是主文件中缺少命名空间。

我找到了这个托管.NET服务http://topshelf-project.com/的框架,这使得开发变得更加容易,并且基本上允许您创建一个可以调试的控制台应用程序,并且还具有内置的Windows / Mono服务安装程序。对我来说唯一的缺点是缺少对InstallUtil.exe的安装支持,但也有一个解决方案。而不是将ServiceProcessInstaller和ServiceInstaller添加到从Installer继承的类中的安装程序覆盖安装和卸载方法,而是使用install / unistall参数运行可执行文件。

[<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)

完整代码:https://gist.github.com/jbezak/eda4cc5864059b717e71beaec47db2d9