Ошибка установки службы Windows (в F#)

Мой вопрос заключается в следующем: при попытке установить службу Windows, я получаю следующую ошибку:

фрагмент кода: ... No public installers with the RunInstallerAttribute.Yes attribute could be found in the <path to exe> assembly. ...

Я следую этому уроку

у меня есть такой Program.fs файл, содержащий:

[<RunInstaller(true)>]
type public FSharpServiceInstaller() =
    inherit Installer()
    do
        < some logic, doesn't really matter >

Этого должно быть достаточно, на самом деле, я даже не думаю, что мне нужно добавить public Ключевое слово для определения типа. Установка этого исполняемого файла с InstallUtil.exe выдает мне ту же ошибку, что и при установке, используя следующий код:

[<EntryPoint>]
let main args =

    if Environment.UserInteractive then
        let parameter = String.Concat(args);
        match parameter with
        | "-i" -> ManagedInstallerClass.InstallHelper [| Assembly.GetExecutingAssembly().Location |]
        | "-u" -> ManagedInstallerClass.InstallHelper [| "/u"; Assembly.GetExecutingAssembly().Location |]
        | _ -> printf "Not allowed!\n" 
    else 
        ServiceBase.Run [| new CreditToolsService() :> ServiceBase |];
    0

Я попытался запустить этот сценарий в PowerShell, cmd и Visual Studio CLI как администратор и моя обычная учетная запись, но я получаю ту же ошибку. Если кто-то знает, что я делаю неправильно, я был бы очень признателен за помощь.

2 ответа

Решение

Хорошо, так что здесь идет...

Я посмотрел на код, предоставленный user1758475, и просто случайно скопировал в приложение решения для вставки. Решение Дона Саймса "просто сработало", и я наконец понял, почему: у меня (и он у него) нет декларации пространства имен в моем источнике. Похоже, это был виновник! После того, как я добавил пространство имен, установщик работал как шарм.

Как указал Курт Николс, установщик не должен быть в модуле, потому что модуль эффективно скрывает тип от вызывающего кода.

Спасибо за помощь в выяснении этого.

Для тех из вас, кто хочет увидеть рабочий пример:

namespace FileWatcher
open System
open System.Reflection
open System.ComponentModel
open System.Configuration.Install
open System.ServiceProcess
open System.IO
open System.Configuration

type FileWatcherService() =
    inherit ServiceBase(ServiceName = "FileWatcher")

    let createEvent = fun (args: FileSystemEventArgs) -> 
                    printf "%s has been %s\n" args.FullPath (args.ChangeType.ToString().ToLower()) 
                    |> ignore

    override x.OnStart(args) =
        let fsw = new FileSystemWatcher ()
        fsw.Path                    <- "C:\TEMP"
        fsw.NotifyFilter            <- NotifyFilters.LastAccess ||| NotifyFilters.LastWrite ||| NotifyFilters.FileName ||| NotifyFilters.DirectoryName ||| NotifyFilters.CreationTime
        fsw.Filter                  <- "*.txt"
        fsw.EnableRaisingEvents     <- true
        fsw.IncludeSubdirectories   <- true
        fsw.Created.Add(createEvent)

    override x.OnStop() =
        printf "Stopping the FileWatcher service"

[<RunInstaller(true)>]
type public 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 = "AAA FileWatcher Service", 
            ServiceName = "AAAFileWatcherService",
            StartType = ServiceStartMode.Automatic )
        |> base.Installers.Add |> ignore


module Program =
    [<EntryPoint>]
    let main args =

        printf "starting the application...\n"


        if Environment.UserInteractive then
            let parameter = String.Concat(args);
            match parameter with
            | "-i" -> ManagedInstallerClass.InstallHelper [| Assembly.GetExecutingAssembly().Location |]
            | "-u" -> ManagedInstallerClass.InstallHelper [| "/u"; Assembly.GetExecutingAssembly().Location |]
            | _ -> printf "Not allowed!\n" 
        else 
            ServiceBase.Run [| new FileWatcherService() :> ServiceBase |];
        0

Пример работающего живого производства по адресу https://github.com/zbilbo/TB4TG/blob/master/TourneyBot.Service/Installer.fs

Думаю, что его нужно установить вместе с InstallUtil.exe.

Возможно, не самый лучший момент в кодировании, но этот конкретный сервисный код от Дона Сайма более или менее: http://blogs.msdn.com/b/dsyme/archive/2011/05/31/a-simple-windows-service-template-for-f.aspx, так что, вероятно, все в порядке, но остальная часть "окружающего" кода в этом хранилище может не быть идиоматичной;-)

Блог Don Symes также объясняет намного больше, поэтому должно быть легко приспособить его к вашим потребностям. Он также ссылается на шаблон службы Win в галерее VS: http://blogs.msdn.com/b/mcsuksoldev/archive/2011/05/31/f-windows-application-template-for-windows-service.aspx

Другие вопросы по тегам