Ошибка установки службы 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