Como criar um instalador para um serviço do Windows .net usando o Visual Studio

Respostas:

227

No projeto de serviço, faça o seguinte:

  1. No gerenciador de soluções, clique duas vezes no arquivo .cs dos serviços. Ele deve exibir uma tela toda cinza e fala sobre arrastar coisas da caixa de ferramentas.
  2. Em seguida, clique com o botão direito do mouse na área cinza e selecione adicionar instalador. Isso adicionará um arquivo de projeto do instalador ao seu projeto.
  3. Em seguida, você terá 2 componentes na exibição de design do ProjectInstaller.cs (serviceProcessInstaller1 e serviceInstaller1). Você deve configurar as propriedades conforme necessário, como nome do serviço e usuário para o qual deve executar.

Agora você precisa fazer um projeto de instalação. A melhor coisa a fazer é usar o assistente de instalação.

  1. Clique com o botão direito do mouse na sua solução e adicione um novo projeto: Adicionar> Novo Projeto> Projetos de Configuração e Implantação> Assistente de Configuração

    uma. Isso pode variar um pouco para diferentes versões do Visual Studio. b. O Visual Studio 2010 está localizado em: Modelos de Instalação> Outros Tipos de Projeto> Instalação e Implantação> Instalador do Visual Studio

  2. Na segunda etapa, selecione "Criar uma instalação para um aplicativo do Windows".

  3. Na terceira etapa, selecione "Saída primária de ..."

  4. Clique em para concluir.

Em seguida, edite seu instalador para garantir que a saída correta esteja incluída.

  1. Clique com o botão direito do mouse no projeto de instalação do Solution Explorer.
  2. Selecione Exibir> Ações personalizadas. (No VS2008, pode ser Exibir> Editor> Ações personalizadas)
  3. Clique com o botão direito do mouse na ação Instalar na árvore Ações personalizadas e selecione 'Adicionar ação personalizada ...'
  4. Na caixa de diálogo "Selecionar item no projeto", selecione Pasta do aplicativo e clique em OK.
  5. Clique em OK para selecionar a opção "Saída primária de ...". Um novo nó deve ser criado.
  6. Repita as etapas 4 a 5 para ações de confirmação, reversão e desinstalação.

Você pode editar o nome da saída do instalador clicando com o botão direito do mouse no projeto Installer em sua solução e selecione Propriedades. Mude o 'Nome do arquivo de saída:' para o que quiser. Selecionando o projeto instalador bem e olhando para as janelas de propriedades, você pode editar o Product Name, Title, Manufacturer, etc ...

Em seguida, crie seu instalador e ele produzirá um MSI e um setup.exe. Escolha o que você deseja usar para implantar seu serviço.

Kelsey
fonte
37
@ El Ronnoco, eu tive a resposta muito antes de postar. Eu queria documentá-lo aqui, porque eu sempre tenho que procurá-lo a cada 6 a 12 meses (e não tem sido tão fácil de encontrar), agora eu o tenho facilmente pesquisável para todos e posso encontrá-lo rapidamente :)
Kelsey
1
Infelizmente, também é a resposta errada. Sim, eu sei que você encontrará isso nos livros e no MSDN, mas é um caso em que um grupo da Microsoft não conversou com outro grupo da Microsoft e encontrou uma solução inferior para um problema que já havia sido resolvido. Consulte blog.iswix.com/2006/07/msi-vs-net.html para obter mais informações.
Christopher Painter
9
@ Christopher Painter Eu uso o instalador da Microsoft desde o 2k5 e ele nunca teve problemas. Se você concorda ou não com isso e o considera um 'antipadrão' não é o objetivo desta pergunta, é como faço x com y, não como faço a com b. Quando publiquei a pergunta, era para fins de documentação.
Kelsey
3
Então você tem sorte há 6 anos e simplesmente não o conhece. Você pode ler: robmensching.com/blog/posts/2007/4/19/…
Christopher Painter
1
Se você receber um Service name contains invalid characters, is empty, or is too long (max length = 80)erro ao adicionar o Instalador, clique com o botão direito do mouse na área cinza novamente, vá para Propriedades e verifique se o valor Nome do Serviço está definido.
wolfyuk
51

Sigo as primeiras etapas de Kelsey para adicionar as classes do instalador ao meu projeto de serviço, mas, em vez de criar um instalador MSI ou setup.exe, eu faço o serviço instalando / desinstalando automaticamente. Aqui está um pouco de código de exemplo de um dos meus serviços que você pode usar como ponto de partida.

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;
}

fonte
1
Por curiosidade, qual é o benefício de ter um serviço de auto-instalação / desinstalação? Se o serviço se instalar, como você o inicia primeiro para que possa ser instalado? Se houver um mecanismo para iniciar o serviço sem instalá-lo, por que se preocupar em instalá-lo?
Kiley Naro
3
@ Christopher - eu não. Minha solução não substitui um instalador completo que você usaria para distribuir software. Estou apresentando outra opção que funciona para algumas situações, como a minha, na qual escrevo software que direciona PCs incorporados em quiosques autônomos.
4
Ao instalá-lo em uma máquina de produção, lembre-se de executá-lo como administrador. Criei um arquivo BAT que chama o arquivo EXE com o parâmetro / i, mas não funcionou no ambiente de produção, mesmo que eu tenha executado o arquivo BAT como administrador. Eu tive que abrir um prompt de linha de comando como administrador e chamar o arquivo EXE / i explicitamente (sem usar o arquivo BAT). Pelo menos que me aconteceu em um Windows Server 2012.
Francisco Goldenstein
1
RE: Nenhuma saída na linha de comando. Usando VS 2017 Community meu projeto serviço novo padrão para tipo de saída: Windows Applicatione objeto de inicialização: (none). Eu tive que mudar o tipo de saída para Console Applicatione definir meu objeto de inicialização, por exemplo myservice.Program. Se houver ramificações que eu não saiba, por favor, informe.
Jonathan
1
O código de exemplo possui erros de digitação? Por que existem três serviços diferentes (CSMessageQueueService, MyService, MyQueueService)?
Nils Guillermin #
27

As soluções Kelsey e Brendan não funcionam para mim na Comunidade do Visual Studio 2015.

Aqui estão minhas breves etapas como criar serviço com o instalador:

  1. Execute o Visual Studio, vá para File->New->Project
  2. Selecione .NET Framework 4, em 'Pesquisar modelos instalados', digite 'Serviço'
  3. Selecione 'Serviço do Windows'. Digite Nome e Local. Pressione OK.
  4. Clique duas vezes em Service1.cs, clique com o botão direito do mouse no designer e selecione 'Adicionar instalador'
  5. Clique duas vezes em ProjectInstaller.cs. Para serviceProcessInstaller1, abra a guia Propriedades e altere o valor da propriedade 'Conta' para 'LocalService'. Para serviceInstaller1, altere 'ServiceName' e defina 'StartType' para 'Automatic'.
  6. Clique duas vezes em serviceInstaller1. Visual Studio cria serviceInstaller1_AfterInstallevento. Escreva o código:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
    
  7. Compilar solução. Clique com o botão direito do mouse no projeto e selecione 'Abrir pasta no File Explorer'. Vá para bin \ Debug .

  8. Crie install.bat com o script abaixo:

    :::::::::::::::::::::::::::::::::::::::::
    :: 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. Criar arquivo uninstall.bat (altere na linha pen-ult /ipara /u)
  10. Para instalar e iniciar o serviço, execute install.bat, para parar e desinstalar, execute uninstall.bat
Alexey Obukhov
fonte
14

Para o VS2017, você precisará adicionar a extensão VS "Microsoft Visual Studio 2017 Installer Projects". Isso fornecerá modelos de projeto adicionais do Visual Studio Installer. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

Para instalar o serviço Windows, você pode adicionar um novo projeto do tipo assistente de configuração e siga as etapas da resposta de Kelsey https://stackoverflow.com/a/9021107/1040040

JustSomeDev
fonte
1

As classes InstallUtil (ServiceInstaller) são consideradas um antipadrão pela comunidade do Windows Installer. É uma reinvenção da roda frágil e fora de processo que ignora o fato de o Windows Installer ter suporte interno para os Serviços.

Os projetos de implantação do Visual Studio (também não são altamente considerados e preteridos na próxima versão do Visual Studio) não têm suporte nativo para serviços. Mas eles podem consumir módulos de mesclagem. Então, eu daria uma olhada neste artigo do blog para entender como criar um módulo de mesclagem usando o Windows Installer XML que pode expressar o serviço e, em seguida, consumir esse módulo de mesclagem na sua solução VDPROJ.

Aprimorando o InstallShield usando o Windows Installer XML - Serviços do Windows

Tutorial de serviço do Windows do IsWiX

Vídeo de Serviço do Windows IsWiX

Christopher Painter
fonte
1
No Visual Studio antigo, havia um projeto de implantação, com fácil instalador de criação. Agora eu tenho que comprar um componente de software de terceiros?
Alexey Obukhov #
@AlexeyObukhov Você pode usar o Wix gratuitamente, é o que o próprio VS usa, mas o problema com o Wix é o mesmo que com o Git - a curva de aprendizado quase vertical.
Alan B