Как запустить .NET-службу Windows сразу после установки?

88

Помимо service.StartType = ServiceStartMode.Automatic моя служба не запускается после установки

Решение

Вставил этот код в мой ProjectInstaller

protected override void OnAfterInstall(System.Collections.IDictionary savedState)
{
    base.OnAfterInstall(savedState);
    using (var serviceController = new ServiceController(this.serviceInstaller1.ServiceName, Environment.MachineName))
        serviceController.Start();
}

Спасибо ScottTx и Francis B.

Джадер Диас
источник
Не запускается сразу после установки или не запускается при перезагрузке?
Крис Ван Опсталь

Ответы:

21

Все это можно сделать из исполняемого файла службы в ответ на события, запускаемые процессом InstallUtil. Переопределите событие OnAfterInstall, чтобы использовать класс ServiceController для запуска службы.

http://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceinstaller.aspx

ScottTx
источник
3
Это хорошее решение, но все же требует использования утилиты InstallUtil. Если вы уже поставляете InstallUtil как часть своей установки, это имеет смысл. Но если вы хотите отказаться от упаковки InstallUtil, используйте решение для командной строки.
Мэтт Дэвис
181

Я отправил процедуру шаг за шагом для создания службы Windows в C # здесь . Похоже, вы по крайней мере дошли до этого момента, и теперь вам интересно, как запустить службу после ее установки. Установка для свойства StartType значения «Автоматически» приведет к автоматическому запуску службы после перезагрузки системы, но она не будет (как вы обнаружили) автоматически запускать службу после установки.

Я не помню, где я его нашел изначально (возможно, Марк Гравелл?), Но я нашел решение в Интернете, которое позволяет вам установить и запустить службу, фактически запустив ее. Вот пошаговая инструкция:

  1. Структурируйте Main()функции вашего сервиса следующим образом:

    static void Main(string[] args)
    {
        if (args.Length == 0) {
            // Run your service normally.
            ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
            ServiceBase.Run(ServicesToRun);
        } else if (args.Length == 1) {
            switch (args[0]) {
                case "-install":
                    InstallService();
                    StartService();
                    break;
                case "-uninstall":
                    StopService();
                    UninstallService();
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }
    
  2. Вот вспомогательный код:

    using System.Collections;
    using System.Configuration.Install;
    using System.ServiceProcess;
    
    private static bool IsInstalled()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                ServiceControllerStatus status = controller.Status;
            } catch {
                return false;
            }
            return true;
        }
    }
    
    private static bool IsRunning()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            if (!IsInstalled()) return false;
            return (controller.Status == ServiceControllerStatus.Running);
        }
    }
    
    private static AssemblyInstaller GetInstaller()
    {
        AssemblyInstaller installer = new AssemblyInstaller(
            typeof(YourServiceType).Assembly, null);
        installer.UseNewContext = true;
        return installer;
    }
    
  3. Продолжая вспомогательный код ...

    private static void InstallService()
    {
        if (IsInstalled()) return;
    
        try {
            using (AssemblyInstaller installer = GetInstaller()) {
                IDictionary state = new Hashtable();
                try {
                    installer.Install(state);
                    installer.Commit(state);
                } catch {
                    try {
                        installer.Rollback(state);
                    } catch { }
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void UninstallService()
    {
        if ( !IsInstalled() ) return;
        try {
            using ( AssemblyInstaller installer = GetInstaller() ) {
                IDictionary state = new Hashtable();
                try {
                    installer.Uninstall( state );
                } catch {
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void StartService()
    {
        if ( !IsInstalled() ) return;
    
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Running ) {
                    controller.Start();
                    controller.WaitForStatus( ServiceControllerStatus.Running, 
                        TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
    
    private static void StopService()
    {
        if ( !IsInstalled() ) return;
        using ( ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Stopped ) {
                    controller.Stop();
                    controller.WaitForStatus( ServiceControllerStatus.Stopped, 
                         TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
    
  4. На этом этапе, после установки службы на целевом компьютере, просто запустите службу из командной строки (как любое обычное приложение) с -installаргументом командной строки, чтобы установить и запустить службу.

Думаю, я рассмотрел все, но если вы обнаружите, что это не работает, сообщите мне, чтобы я мог обновить ответ.

Мэтт Дэвис
источник
12
Обратите внимание, что это решение не требует использования InstallUtil.exe, поэтому вам не нужно доставлять его как часть программы установки.
Мэтт Дэвис
3
Какой смысл в пустых предложениях "catch {throw;}"? Кроме того, вероятно, не рекомендуется скрывать сбои с помощью "Rollback ()", поскольку эта ситуация в основном оставляет систему в неопределенном состоянии, я думаю (вы пытались установить службу, но не смогли ее отменить. ). Вы должны хотя бы «показать» пользователю, что есть что-то подозрительное - или функция Rollback () пишет какие-то сообщения в консоль?
Christian.K
5
Откат действительно записывает данные в консоль. Что касается пустых блоков catch, то это дело отладки. Я могу поставить точку останова в операторе throw для проверки любых возможных исключений.
Мэтт Дэвис,
4
Я получаю сообщение об ошибке Ошибка: не удалось найти тип или имя пространства имен YourServiceType (вам не хватает директивы using или ссылки на сборку?
Йогеш
5
YourServiceTypeэто то, что ProjectInstallerвы добавили в сервис, который содержит ServiceInstallerиServiceProcessInstaller
bansi
6

Visual Studio

Если вы создаете проект установки с помощью VS, вы можете создать настраиваемое действие, которое вызывает метод .NET для запуска службы. Но на самом деле не рекомендуется использовать управляемое настраиваемое действие в MSI. См. Эту страницу .

ServiceController controller  = new ServiceController();
controller.MachineName = "";//The machine where the service is installed;
controller.ServiceName = "";//The name of your service installed in Windows Services;
controller.Start();

InstallShield или Wise

Если вы используете InstallShield или Wise, эти приложения предоставляют возможность запустить службу. Например, с Wise вам нужно добавить действие по управлению службой. В этом действии вы указываете, хотите ли вы запустить или остановить службу.

Wix

Используя Wix, вам необходимо добавить следующий xml-код под компонент вашей службы. Для получения дополнительной информации об этом вы можете проверить эту страницу .

<ServiceInstall 
    Id="ServiceInstaller"  
    Type="ownProcess"  
    Vital="yes"  
    Name=""  
    DisplayName=""  
    Description=""  
    Start="auto"  
    Account="LocalSystem"   
    ErrorControl="ignore"   
    Interactive="no">  
        <ServiceDependency Id="????"/> ///Add any dependancy to your service  
</ServiceInstall>
Фрэнсис Б.
источник
5

Вам необходимо добавить настраиваемое действие в конец последовательности ExecuteImmediate в MSI, используя имя компонента EXE или пакета (sc start) в качестве источника. Я не думаю, что это можно сделать с помощью Visual Studio, возможно, вам придется использовать для этого настоящий инструмент разработки MSI.

Отавио Десио
источник
4

Чтобы запустить его сразу после установки, я создаю командный файл с installutil, за которым следует sc start

Не идеально, но работает ....

Мэтт
источник
4

Используйте класс .NET ServiceController для его запуска или введите команду командной строки, чтобы запустить его - «net start servicename». В любом случае работает.

ScottTx
источник
4

Чтобы добавить к ответу ScottTx, вот фактический код для запуска службы, если вы делаете это способом Microsoft (например, используя проект установки и т. Д.)

(извините за код VB.net, но это то, с чем я застрял)

Private Sub ServiceInstaller1_AfterInstall(ByVal sender As System.Object, ByVal e As System.Configuration.Install.InstallEventArgs) Handles ServiceInstaller1.AfterInstall
    Dim sc As New ServiceController()
    sc.ServiceName = ServiceInstaller1.ServiceName

    If sc.Status = ServiceControllerStatus.Stopped Then
        Try
            ' Start the service, and wait until its status is "Running".
            sc.Start()
            sc.WaitForStatus(ServiceControllerStatus.Running)

            ' TODO: log status of service here: sc.Status
        Catch ex As Exception
            ' TODO: log an error here: "Could not start service: ex.Message"
            Throw
        End Try
    End If
End Sub

Чтобы создать указанный выше обработчик событий, перейдите в конструктор ProjectInstaller, где находятся 2 элемента управления. Щелкните элемент управления ServiceInstaller1. Перейдите в окно свойств под событиями, и там вы найдете событие AfterInstall.

Примечание. Не помещайте приведенный выше код в событие AfterInstall для ServiceProcessInstaller1. Исходя из опыта, это не сработает. :)

goku_da_master
источник
Код VB.net неплохой! Для тех из нас, кто работает на нескольких языках, приятно не конвертировать код из C!
Стив Рид-старший
Спасибо, это помогло мне понять, как автоматически запускать службу.
Чарльз Оуэн,
0

Самое простое решение находится здесь install-windows-service-without-installutil-exe от @ Hoàng Long

@echo OFF
echo Stopping old service version...
net stop "[YOUR SERVICE NAME]"
echo Uninstalling old service version...
sc delete "[YOUR SERVICE NAME]"

echo Installing service...
rem DO NOT remove the space after "binpath="!
sc create "[YOUR SERVICE NAME]" binpath= "[PATH_TO_YOUR_SERVICE_EXE]" start= auto
echo Starting server complete
pause
Роберт Грин, MBA
источник