Как создать установщик для .net Windows Service с использованием Visual Studio

Ответы:

227

В сервисном проекте сделайте следующее:

  1. В обозревателе решений дважды щелкните файл .cs вашего сервиса. Это должно вызвать экран, который весь серый и говорит о перетаскивании материала из панели инструментов.
  2. Затем щелкните правой кнопкой мыши на серой области и выберите «Добавить установщик». Это добавит файл проекта установщика в ваш проект.
  3. Затем у вас будет 2 компонента в представлении конструктора ProjectInstaller.cs (serviceProcessInstaller1 и serviceInstaller1). Затем вы должны настроить свойства, которые вам нужны, такие как имя службы и пользователя, под которым он должен работать.

Теперь вам нужно сделать проект установки. Лучше всего использовать мастер установки.

  1. Щелкните правой кнопкой мыши свое решение и добавьте новый проект: Добавить> Новый проект> Проекты установки и развертывания> Мастер установки

    а. Это может незначительно отличаться для разных версий Visual Studio. б. Visual Studio 2010 находится в: Шаблоны установки> Другие типы проектов> Установка и развертывание> Установщик Visual Studio

  2. На втором шаге выберите «Создать установку для приложения Windows».

  3. На третьем шаге выберите «Первичный выход из ...»

  4. Нажмите, чтобы закончить.

Затем отредактируйте ваш установщик, чтобы убедиться, что включен правильный вывод.

  1. Щелкните правой кнопкой мыши по проекту установки в обозревателе решений.
  2. Выберите «Просмотр»> «Пользовательские действия». (В VS2008 это может быть View> Editor> Custom Actions)
  3. Щелкните правой кнопкой мыши действие Install в дереве пользовательских действий и выберите «Добавить пользовательское действие ...»
  4. В диалоговом окне «Выбрать элемент в проекте» выберите «Папка приложения» и нажмите «ОК».
  5. Нажмите OK, чтобы выбрать опцию «Первичный вывод из ...». Новый узел должен быть создан.
  6. Повторите шаги 4 - 5 для фиксации, отката и удаления действий.

Вы можете отредактировать выходное имя установщика, щелкнув правой кнопкой мыши проект установщика в своем решении и выбрав Свойства. Измените «Имя выходного файла:» на любое другое. Выбирая проект установки , а также и глядя на окна свойств, вы можете редактировать Product Name, Title, Manufacturerи т.д. ...

Затем соберите установщик, и он создаст MSI и файл setup.exe. Выберите тот, который вы хотите использовать для развертывания вашего сервиса.

Kelsey
источник
37
@ El Ronnoco, у меня был ответ задолго до того, как я написал. Я хотел документировать это здесь, потому что мне всегда приходится искать его каждые 6 - 12 месяцев (и это было не так легко найти), так что теперь у меня есть его легко найти для всех, и я могу найти его сам быстро :)
Келси
1
К сожалению, это также неправильный ответ. Да, я знаю, вы найдете это в книгах и MSDN, но это тот случай, когда одна группа в Microsoft не общалась с другой группой в Microsoft и придумала более низкое решение проблемы, которая уже была решена. См. Blog.iswix.com/2006/07/msi-vs-net.html для получения дополнительной информации.
Кристофер Пэйнтер
9
@Christopher Painter Я использую установщик MS с 2k5, и у него никогда не было проблем. Согласны ли вы с этим и считаете ли вы его «анти-паттерном», вопрос не в этом, а в том, как я делаю х с у, а не как я делаю а с б. Когда я отправил вопрос, это было в целях документации.
Келси
3
Тогда тебе повезло в течение 6 лет, ты просто не знаешь этого. Возможно, вы захотите прочитать: robmensching.com/blog/posts/2007/4/19/…
Кристофер Пейнтер
1
Если Service name contains invalid characters, is empty, or is too long (max length = 80)при добавлении установщика появляется ошибка, снова щелкните правой кнопкой мыши в серой области, перейдите в Свойства и убедитесь, что установлено значение Имя службы.
Вольфюк
51

Я следую первому набору шагов Келси, чтобы добавить классы установщика в мой сервисный проект, но вместо создания установщика MSI или setup.exe я делаю сервис самостоятельно устанавливаемым / удаляемым. Вот пример кода из одного из моих сервисов, который вы можете использовать в качестве отправной точки.

public static int Main(string[] args)
{
    if (System.Environment.UserInteractive)
    {
        // we only care about the first two characters
        string arg = args[0].ToLowerInvariant().Substring(0, 2);

        switch (arg)
        {
            case "/i":  // install
                return InstallService();

            case "/u":  // uninstall
                return UninstallService();

            default:  // unknown option
                Console.WriteLine("Argument not recognized: {0}", args[0]);
                Console.WriteLine(string.Empty);
                DisplayUsage();
                return 1;
        }
    }
    else
    {
        // run as a standard service as we weren't started by a user
        ServiceBase.Run(new CSMessageQueueService());
    }

    return 0;
}

private static int InstallService()
{
    var service = new MyService();

    try
    {
        // perform specific install steps for our queue service.
        service.InstallService();

        // install the service with the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

private static int UninstallService()
{
    var service = new MyQueueService();

    try
    {
        // perform specific uninstall steps for our queue service
        service.UninstallService();

        // uninstall the service from the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service not installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

источник
1
Из любопытства, какая польза от самостоятельной установки / удаления службы? Если служба устанавливается сама, как вы запускаете службу первой, чтобы ее можно было установить в первую очередь? Если есть механизм запуска службы без ее установки, зачем вообще его устанавливать?
Кили Наро
3
@ Кристофер - нет. Мое решение не является заменой полного установщика, который вы бы использовали для распространения программного обеспечения. Я представляю другой вариант, который работает в некоторых ситуациях, например, мой, где я пишу программное обеспечение, которое управляет встроенными ПК в автоматических киосках.
4
Когда вы устанавливаете его на рабочий компьютер, не забудьте запустить его от имени администратора. Я создал BAT-файл, который вызывает EXE-файл с параметром / i, но он не работал в производственной среде, хотя я выполнял BAT-файл от имени администратора. Мне пришлось открыть приглашение командной строки от имени администратора и явно вызвать файл EXE / I (без использования файла BAT). По крайней мере, это случилось со мной на Windows Server 2012.
Франсиско Гольдштейн
1
RE: Нет вывода в командной строке. Использование VS 2017 Сообщество мой новый проект службы по умолчанию для типа вывода: Windows Applicationи объекта запуска: (none). Мне пришлось изменить тип вывода на Console Applicationи установить мой объект запуска, например myservice.Program. Если могут быть последствия, о которых я не знаю, пожалуйста, сообщите.
Джонатан
1
В примере кода есть опечатки? Почему существуют три разных сервиса (CSMessageQueueService, MyService, MyQueueService)?
Нильс Гильермин
27

Ни Kelsey, ни Brendan solutions не работают для меня в сообществе Visual Studio 2015.

Вот мои краткие шаги, как создать сервис с установщиком:

  1. Запустите Visual Studio, перейдите к File->New->Project
  2. Выберите .NET Framework 4 в поле «Поиск установленных шаблонов» введите «Сервис».
  3. Выберите «Служба Windows». Введите имя и местоположение. НажмитеOK .
  4. Дважды щелкните Service1.cs, щелкните правой кнопкой мыши в конструкторе и выберите «Добавить установщик».
  5. Дважды щелкните ProjectInstaller.cs. Для serviceProcessInstaller1 откройте вкладку «Свойства» и измените значение свойства «Account» на «LocalService». Для serviceInstaller1 измените «ServiceName» и установите «StartType» на «Автоматический».
  6. Дважды щелкните сервисInstaller1. Visual Studio создает serviceInstaller1_AfterInstallсобытие. Написать код:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
  7. Построить решение. Щелкните правой кнопкой мыши по проекту и выберите «Открыть папку в проводнике». Перейдите в bin \ Debug .

  8. Создайте install.bat с помощью приведенного ниже скрипта:

    :::::::::::::::::::::::::::::::::::::::::
    :: Automatically check & get admin rights
    :::::::::::::::::::::::::::::::::::::::::
    @echo off
    CLS 
    ECHO.
    ECHO =============================
    ECHO Running Admin shell
    ECHO =============================
    
    :checkPrivileges 
    NET FILE 1>NUL 2>NUL
    if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges ) 
    
    :getPrivileges 
    if '%1'=='ELEV' (shift & goto gotPrivileges)  
    ECHO. 
    ECHO **************************************
    ECHO Invoking UAC for Privilege Escalation 
    ECHO **************************************
    
    setlocal DisableDelayedExpansion
    set "batchPath=%~0"
    setlocal EnableDelayedExpansion
    ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs" 
    ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs" 
    "%temp%\OEgetPrivileges.vbs" 
    exit /B 
    
    :gotPrivileges 
    ::::::::::::::::::::::::::::
    :START
    ::::::::::::::::::::::::::::
    setlocal & pushd .
    
    cd /d %~dp0
    %windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /i "WindowsService1.exe"
    pause
  9. Создайте файл uninstall.bat (измените строку pen-ult /iна/u )
  10. Для установки и запуска службы запустите install.bat, для остановки и удаления запустите uninstall.bat
Алексей Обухов
источник
14

Для VS2017 вам необходимо добавить расширение VS «Проекты установщика Microsoft Visual Studio 2017». Это даст вам дополнительные шаблоны проектов Visual Studio Installer. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

Чтобы установить службу Windows, вы можете добавить новый тип проекта мастера установки и выполнить действия из ответа Келси https://stackoverflow.com/a/9021107/1040040.

JustSomeDev
источник
1

Классы InstallUtil (ServiceInstaller) рассматриваются сообществом установщика Windows как анти-шаблон. Это хрупкое, не в процессе, переизобретение колеса, которое игнорирует тот факт, что установщик Windows имеет встроенную поддержку служб.

Проекты развертывания Visual Studio (также не высоко оцененные и не рекомендуемые в следующем выпуске Visual Studio) не имеют встроенной поддержки служб. Но они могут потреблять модули слияния. Поэтому я хотел бы взглянуть на эту статью блога, чтобы понять, как создать модуль слияния с помощью установщика Windows XML, который может выражать службу, а затем использовать этот модуль слияния в вашем решении VDPROJ.

Дополнение InstallShield с помощью установщика Windows XML - Службы Windows

IsWiX Windows Service Tutorial

IsWiX Windows Сервис Видео

Кристофер Пейнтер
источник
1
В старой Visual Studio существовал проект развертывания, с легким созданием установщика. Теперь я должен купить сторонний программный компонент?
Алексей Обухов
@AlexeyObukhov Вы можете использовать Wix бесплатно, это то, что использует сама VS, но проблема с Wix такая же, как и с Git - почти вертикальная кривая обучения.
Алан Б