Maneira mais fácil de depurar um serviço do Windows

325

Existe uma maneira mais fácil de percorrer o código do que iniciar o serviço por meio do Windows Service Control Manager e depois anexar o depurador ao encadeamento? É meio complicado e estou me perguntando se existe uma abordagem mais direta.

Matthias
fonte
Eu criei este tíquete de voz do usuário. Considere voto para ele: visualstudio.uservoice.com/forums/121579-visual-studio-ide/...
David

Respostas:

271

Se eu quiser depurar rapidamente o serviço, simplesmente entrei Debugger.Break()lá. Quando essa linha é alcançada, ela volta ao VS. Não se esqueça de remover essa linha quando terminar.

ATUALIZAÇÃO: Como alternativa aos #if DEBUGpragmas, você também pode usar o Conditional("DEBUG_SERVICE")atributo.

[Conditional("DEBUG_SERVICE")]
private static void DebugMode()
{
    Debugger.Break();
}

No seu caso OnStart, basta chamar este método:

public override void OnStart()
{
     DebugMode();
     /* ... do the rest */
}

Lá, o código será ativado apenas durante as compilações de depuração. Enquanto você estiver trabalhando nisso, pode ser útil criar uma Configuração de Compilação separada para depuração do serviço.

piada
fonte
45
Ou você pode usar Debugger.Launch (), incluindo uma instrução using para o espaço de nome The Systems.Diagnostics.
Omar Kooheji
1
Seu post funcionou bem e salvou meu dia :) no entanto, o Debugger.Break () não funcionou para mim. parece que .Net ignora a função DebugMode por alguns motivos relacionados à otimização.
Bizhan
3
Debugger.Launch () funciona para mim quando Debugger.Break () não. (O processo é encerrado com o código 255.)
Oliver Bock
Como vocês estão fazendo isso funcionar? Nada acontece. Eu tentei Break () e Launch ().
4thSpace 22/03
13
@ 4thSpace: 1. crie um instalador para o seu serviço, para que você possa instalá-lo. 2. Adicione a linha Debugger.Launch (); no início do seu Main (). 3. Crie seu código no modo de depuração. 4. Sobrescreva as DLLs instaladas pelas DLLs de depuração. 5. Inicie o serviço no painel Serviços do Windows. Agora, um pop-up aparece para solicitar que você se conecte a um depurador. Dessa forma, funcionou para mim. Espero que você também.
Ffonz
210

Também acho que ter uma "versão" separada para execução normal e como serviço é o caminho a percorrer, mas é realmente necessário dedicar uma opção de linha de comando separada para esse fim?

Você não poderia simplesmente fazer:

public static int Main(string[] args)
{
  if (!Environment.UserInteractive)
  {
    // Startup as service.
  }
  else
  {
    // Startup as application
  }
}

Isso teria o "benefício", que você pode simplesmente iniciar seu aplicativo via clique duplo (OK, se você realmente precisar disso) e clicar F5no Visual Studio (sem a necessidade de modificar as configurações do projeto para incluir isso)/console opção).

Tecnicamente, Environment.UserInteractiveverifica se o WSF_VISIBLESinalizador está definido para a estação atual da janela, mas existe algum outro motivo para retornar false, além de ser executado como um serviço (não interativo)?

Christian.K
fonte
Ótimo! Anteriormente, usei um método "if #debug" para iniciar como aplicativo se estiver depurando, caso contrário, um serviço. Isso faz com que o aplicativo não seja executável como um serviço se você deseja depurá-lo, mas sua solução resolve isso e permite que seja executável nas quatro combinações de serviço / aplicativo e liberação / depuração.
Jonas
29
Se você não quiser que o programa seja executado com um clique duplo (os usuários podem ficar confusos e executar várias instâncias, etc.), use-o em System.Diagnostics.Debugger.IsAttachedvez de Environment.UserInteractive.
Blorgbeard sai
5
mas existe outro motivo pelo qual ele retornaria falso, além de ser executado como um serviço (não interativo)? Posso pensar em uma delas: uma tarefa agendada que não se conecta a um console.
Hogan
7
Eu uso parâmetros de linha de comando para este caso. --install para instalar o serviço, --uninstall para desinstalar o serviço e --interactive para executar o serviço como aplicativo. eu adiciono --interactive às opções do projeto (Debugging> Command Arguments). Para que eu possa depurar facilmente do VS. clicar duas vezes não criará uma instância em execução indesejada, pois --interactive é necessário. apenas meus 2 centavos.
emir Akaydın
@ EmirAkaydın Sim, na verdade eu tenho parâmetros de linha de comando como "backup" também. No entanto, eu realmente queria ter uma instância "interativa" ao clicar duas vezes e não e uma mensagem de erro sobre o fato de que um serviço não pode ser iniciado dessa maneira. Variando metas acho ;-)
Christian.K
123

Quando configurei um novo projeto de serviço, há algumas semanas, encontrei este post. Embora haja muitas ótimas sugestões, ainda não encontrei a solução que queria: a possibilidade de chamar as classes de serviço OnStarteOnStop métodos sem nenhuma modificação nas classes de serviço.

A solução que eu criei usa o Environment.Interactivemodo de execução select, conforme sugerido por outras respostas a este post.

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

O RunInteractiveauxiliar usa reflexão para chamar os métodos protected OnStarte OnStop:

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();

    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();

    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }

    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1000);
}

Este é todo o código necessário, mas também escrevi orientações com explicações.

Anders Abel
fonte
Isso é um bom método de extensão para o ServiceBase []. Eu tenho vários serviços em minha solução, portanto, em vez de ter uma classe base comum para Program.cs, eu chamo apenas servicesToRun.RunInteractive (args). Boa solução @ Anders!
precisa saber é o seguinte
3
Ótima solução, de fato. Eu criei uma extensão simples para ServiceBase [] como David sugeriu que permite executar serviços em apenas uma linha de código: pastebin.com/F0fhhG2R
Funbit
4
+1 Um ex-colega meu criou uma classe base "EasyRunService" (que herda ServiceProcess) que faz praticamente a mesma coisa, mas sem a necessidade de reflexão (porque o OnStart agora está na classe base). Realmente facilita a depuração de um serviço do Windows.
Sondergard
3
@ Chazt3n Verifique se o tipo de saída do seu projeto está definido como "Aplicativo de Console". Quanto à instalação do serviço, independentemente do tipo de saída selecionado, o comportamento é o mesmo.
Funbit
2
Ainda é uma ótima solução! A única coisa que eu adicionaria (como mostrado na walk through) é garantir que você vá para as propriedades do projeto e altere o tipo de saída para Console Applicationantes de tentar compilar e executar. Encontre-o em Project Properties -> Application -> Output type -> Console Application. Além disso, para que isso funcionasse corretamente, acabei tendo que executar o aplicativo usando o startcomando Ex: C:\"my app name.exe" -servicenão funcionaria para mim. Em vez disso eu useiC:\start /wait "" "my app name.exe" -service
Arvo Bowen
47

Às vezes, é importante analisar o que está acontecendo durante a inicialização do serviço. Anexar ao processo não ajuda aqui, porque você não é rápido o suficiente para anexar o depurador enquanto o serviço está sendo iniciado.

A resposta curta é: estou usando as 4 linhas de código a seguir para fazer isso:

#if DEBUG
    base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
    Debugger.Launch(); // launch and attach debugger
#endif

Eles são inseridos no OnStartmétodo do serviço da seguinte maneira:

protected override void OnStart(string[] args)
{
    #if DEBUG
       base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
       Debugger.Launch(); // launch and attach debugger
    #endif
    MyInitOnstart(); // my individual initialization code for the service
    // allow the base class to perform any work it needs to do
    base.OnStart(args);
}

Para aqueles que não fizeram isso antes, incluímos dicas detalhadas abaixo , porque você pode facilmente ficar preso. As dicas a seguir se referem ao Windows 7x64 e ao Visual Studio 2010 Team Edition , mas também devem ser válidas para outros ambientes.


Importante: Implemente o serviço no modo "manual" (usando o InstallUtilutilitário no prompt de comandos do VS ou execute um projeto do instalador de serviço que você preparou). Abra o Visual Studio antes de iniciar o serviço e carregue a solução que contém o código-fonte do serviço - configure pontos de interrupção adicionais conforme necessário no Visual Studio - e inicie o serviço via Painel de Controle Serviço.

Devido ao Debugger.Launchcódigo, isso causará uma caixa de diálogo "Ocorreu uma exceção não tratada do Microsoft .NET Framework no Servicename.exe ". aparecer. Clique como mostrado na captura de tela:Elevate Yes, debug Servicename.exe
FrameworkException

Posteriormente, principalmente no UAC do Windows 7, você poderá solicitar credenciais de administrador. Digite-os e continue com Yes:

UACPrompt

Depois disso, a janela conhecida do depurador just-in-time do Visual Studio é exibida. Ele pergunta se você deseja depurar usando o depurador excluído. Antes de clicar Yes, selecione que você não deseja abrir uma nova instância (segunda opção) - uma nova instância não seria útil aqui, porque o código-fonte não seria exibido. Então você seleciona a instância do Visual Studio que você abriu anteriormente: VSDebuggerPrompt

Depois de clicar Yes, depois de um tempo, o Visual Studio mostrará a seta amarela na linha em Debugger.Launchque está a instrução e você poderá depurar seu código (método MyInitOnStart, que contém sua inicialização). VSDebuggerBreakpoint

Pressionar F5continua a execução imediatamente, até o próximo ponto de interrupção que você preparou.

Dica: Para manter o serviço em execução, selecione Depurar -> Desanexar tudo . Isso permite que você execute um cliente se comunicando com o serviço depois que ele foi iniciado corretamente e você terminou de depurar o código de inicialização. Se você pressionar Shift+F5 (parar a depuração), isso encerrará o serviço. Em vez de fazer isso, você deve usar o Painel de Controle do Serviço para interrompê-lo.

Note que

  • Se você criar uma versão, o código de depuração será automaticamente removido e o serviço será executado normalmente.

  • Estou usando Debugger.Launch(), que inicia e anexa um depurador . Também testei Debugger.Break(), o que não funcionou , porque ainda não existe um depurador conectado na inicialização do serviço (causando o "Erro 1067: O processo foi encerrado inesperadamente" ).

  • RequestAdditionalTimedefine um longo tempo de espera para o arranque do serviço (que é não atrasar o código em si, mas vai continuar imediatamente com aDebugger.Launch declaração). Caso contrário, o tempo limite padrão para iniciar o serviço é muito curto e o serviço falhará se você não ligar com base.Onstart(args)rapidez suficiente no depurador. Praticamente, um tempo limite de 10 minutos evita que você veja a mensagem " o serviço não respondeu ..." imediatamente após o início do depurador.

  • Depois de se acostumar, esse método é muito fácil, pois exige apenas a adição de 4 linhas a um código de serviço existente, permitindo que você obtenha rapidamente controle e depuração.

Matt
fonte
1
Por curiosidade, você sabe se existe um tempo limite para a interação do usuário com o prompt do usuário Debugger.Launch ()?
Shiv
1
Conforme descrito, base.RequestAdditionalTime(600000)impedirá que o controle de serviço encerre o serviço por 10 minutos, se ele não ligar base.OnStart(args)dentro desse prazo). Além disso, lembro que o UAC também será abortado se você não inserir as credenciais de administrador depois de um tempo (não sei exatamente quantos segundos, mas acho que você deve inseri-lo em um minuto, caso contrário, o UAC anula) , que encerrará a sessão de depuração.
Matt
2
Eu achei que esse era o melhor método para depurar mensagens CustomCommand. +1.
23716 Justin
40

O que eu costumo fazer é encapsular a lógica do serviço em uma classe separada e iniciá-la a partir de uma classe 'runner'. Essa classe de corredor pode ser o serviço real ou apenas um aplicativo de console. Portanto, sua solução possui (pelo menos) três projetos:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....
Paul van Brenk
fonte
1
Eu costumava usar essa abordagem também, mas acho que uma combinação disso e da resposta acima funciona muito bem.
rouba
27

Este vídeo do YouTube de Fabio Scopel explica como depurar um serviço do Windows bastante bem ... o método real de fazer isso começa às 4:45 no vídeo ...

Aqui está o código explicado no vídeo ... no seu arquivo Program.cs, adicione o material para a seção Debug ...

namespace YourNamespace
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
#if DEBUG
            Service1 myService = new Service1();
            myService.OnDebug();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
#endif

        }
    }
}

No seu arquivo Service1.cs, adicione o método OnDebug () ...

    public Service1()
    {
        InitializeComponent();
    }

    public void OnDebug()
    {
        OnStart(null);
    }

    protected override void OnStart(string[] args)
    {
        // your code to do something
    }

    protected override void OnStop()
    {
    }

Como funciona

Basicamente, você precisa criar um public void OnDebug()que chame o OnStart(string[] args)como está protegido e não pode ser acessado fora. O void Main()programa é adicionado com o #ifpré-processador com #DEBUG.

O Visual Studio define DEBUGse o projeto é compilado no modo de Depuração. Isso permitirá que a seção de depuração (abaixo) seja executada quando a condição for verdadeira

Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

E ele será executado como um aplicativo de console. Quando tudo der certo, você poderá alterar o modo Releasee a elseseção regular ativará a lógica.

Jason Miller
fonte
Eu estava procurando por essa resposta, não sei por que ela era tão baixa. Explicou o código para ajudar outras pessoas ou, possivelmente, mais comentários;)
Vinod Srivastav
14

ATUALIZAR

Essa abordagem é de longe a mais fácil:

http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx

Deixo minha resposta original abaixo para a posteridade.


Meus serviços tendem a ter uma classe que encapsula um Timer, pois quero que o serviço verifique regularmente se existe algum trabalho para ele fazer.

Iniciamos a classe e chamamos StartEventLoop () durante a inicialização do serviço. (Essa classe também pode ser usada com facilidade em um aplicativo de console.)

O bom efeito colateral desse design é que os argumentos com os quais você configurou o Timer podem ter um atraso antes que o serviço realmente comece a funcionar, para que você tenha tempo para anexar um depurador manualmente.

ps Como anexar o depurador manualmente a um processo em execução ...?

using System;
using System.Threading;
using System.Configuration;    

public class ServiceEventHandler
{
    Timer _timer;
    public ServiceEventHandler()
    {
        // get configuration etc.
        _timer = new Timer(
            new TimerCallback(EventTimerCallback)
            , null
            , Timeout.Infinite
            , Timeout.Infinite);
    }

    private void EventTimerCallback(object state)
    {
        // do something
    }

    public void StartEventLoop()
    {
        // wait a minute, then run every 30 minutes
        _timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
    }
}

Também costumava fazer o seguinte (já mencionado nas respostas anteriores, mas com os sinalizadores do compilador condicional [#if] para ajudar a evitar o disparo em uma versão).

Parei de fazê-lo dessa maneira, porque às vezes esquecíamos de criar o Release e interrompíamos o depurador em um aplicativo em execução em uma demonstração do cliente (embaraçoso!).

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif
rohancragg
fonte
O que acontece quando // do somethingleva mais de 30 minutos para ser concluído?
Vinod Srivastav 22/10
13

static void Main()
{
#if DEBUG
                // Run as interactive exe in debug mode to allow easy
                // debugging.

                var service = new MyService();
                service.OnStart(null);

                // Sleep the main thread indefinitely while the service code
                // runs in .OnStart

                Thread.Sleep(Timeout.Infinite);
#else
                // Run normally as service in release mode.

                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]{ new MyService() };
                ServiceBase.Run(ServicesToRun);
#endif
}
Thomas Bratt
fonte
[Desculpe por nenhuma explicação com os problemas de remarcação de código] Deve ser executado normalmente no MS Visual Studio (F5) nas versões de depuração. Ainda é executado como um serviço normal nas compilações de versão.
Thomas Bratt
Combine isso com a solução acima apresentada por Christian K. para usar a propriedade "Environment.UserInteractive" e a solução é realmente limpa e simples.
Ben Robbins
OnStarté protectede você não pode modificar o nível de acesso :(
Eduard Luca
10

Você também pode iniciar o serviço através do prompt de comando (sc.exe).

Pessoalmente, eu executaria o código como um programa independente na fase de depuração e, quando a maioria dos erros for resolvida, mude para execução como serviço.

akauppi
fonte
10

O que eu costumava fazer era ter uma opção de linha de comando que iniciasse o programa como um serviço ou como um aplicativo regular. Então, no meu IDE, eu definiria a opção para que eu pudesse percorrer meu código.

Em alguns idiomas, é possível detectar se ele está sendo executado em um IDE e executar essa opção automaticamente.

Que linguagem você está usando?

RB.
fonte
9

Use a biblioteca TopShelf .

Crie um aplicativo de console e defina a configuração no seu Main

class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {

                // setup service start and stop.
                x.Service<Controller>(s =>
                {
                    s.ConstructUsing(name => new Controller());
                    s.WhenStarted(controller => controller.Start());
                    s.WhenStopped(controller => controller.Stop());
                });

                // setup recovery here
                x.EnableServiceRecovery(rc =>
                {
                    rc.RestartService(delayInMinutes: 0);
                    rc.SetResetPeriod(days: 0);
                });

                x.RunAsLocalSystem();
            });
        }
}

public class Controller
    {
        public void Start()
        {

        }

        public void Stop()
        {

        }
    }

Para depurar seu serviço, basta pressionar F5 no visual studio.

Para instalar o serviço, digite cmd "console.exe install"

Você pode iniciar e interromper o serviço no gerenciador de serviços do Windows.

Misterhex
fonte
Seu licenciamento era muito confuso para entender
l
Eles usam o Apache License afaik. A prateleira superior é a maneira mais fácil de usar para desenvolver e depurar serviços do Windows. Super fácil de usar. Desenvolva como um aplicativo de console. Instale como um serviço com uma opção de linha de comando. Altamente recomendado.
rouba 23/01
O TopShelf me salvou muito tempo. Thx
L_7337
8

Eu acho que depende do sistema operacional que você estiver usando, o Vista é muito mais difícil de conectar aos Serviços, devido à separação entre as sessões.

As duas opções que usei no passado são:

  • Use GFlags (nas Ferramentas de depuração para Windows) para configurar um depurador permanente para um processo. Isso existe na chave de registro "Opções de execução de arquivo de imagem" e é incrivelmente útil. Eu acho que você precisará ajustar as configurações do serviço para ativar o "Interagir com a área de trabalho". Eu uso isso para todos os tipos de depuração, não apenas serviços.
  • A outra opção é separar um pouco o código, para que a parte do serviço seja intercambiável com uma inicialização normal do aplicativo. Dessa forma, você pode usar um sinalizador de linha de comando simples e iniciar como um processo (em vez de um Serviço), o que facilita muito a depuração.

Espero que isto ajude.

RichS
fonte
+1 para GFlags. Isso é especialmente útil se você não puder modificar o código fonte (ou se não o tiver).
Chris Gillum
6

Eu gosto de poder depurar todos os aspectos do meu serviço, incluindo qualquer inicialização no OnStart (), enquanto ainda o executo com comportamento de serviço completo dentro da estrutura do SCM ... sem modo "console" ou "aplicativo".

Eu faço isso criando um segundo serviço, no mesmo projeto, para usar na depuração. O serviço de depuração, quando iniciado como de costume (ou seja, no plug-in MMC de serviços), cria o processo de host do serviço. Isso fornece um processo ao qual anexar o depurador, mesmo que você ainda não tenha iniciado seu serviço real. Após anexar o depurador ao processo, inicie o serviço real e você poderá entrar nele em qualquer lugar do ciclo de vida do serviço, incluindo OnStart ().

Como requer uma intrusão mínima de código, o serviço de depuração pode ser facilmente incluído no seu projeto de configuração de serviço e é facilmente removido do seu release de produção, comentando uma única linha de código e excluindo um único instalador do projeto.

Detalhes:

1) Supondo que você esteja implementando MyService, também crie MyServiceDebug. Adicione ambos à ServiceBasematriz da seguinte Program.csmaneira:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new MyService(),
            new MyServiceDebug()
        };
        ServiceBase.Run(ServicesToRun);
    }

2) Adicione o serviço real E o serviço de depuração ao instalador do projeto:

insira a descrição da imagem aqui

Ambos os serviços (real e depuração) são incluídos quando você adiciona a saída do projeto de serviço ao projeto de instalação do serviço. Após a instalação, os dois serviços aparecerão no plug-in service.msc MMC.

3) Inicie o serviço de depuração no MMC.

4) No Visual Studio, conecte o depurador ao processo iniciado pelo serviço de depuração.

5) Inicie o serviço real e aproveite a depuração.

BitMask777
fonte
5

Quando escrevo um serviço, coloco toda a lógica de serviço em um projeto de DLL e crio dois "hosts" que chamam nessa DLL, um é um serviço do Windows e o outro é um aplicativo de linha de comando.

Uso o aplicativo de linha de comando para depuração e anexo o depurador ao serviço real apenas para erros que não consigo reproduzir no aplicativo de linha de comando.

Se você usar essa abordagem, lembre-se de que é necessário testar todo o código enquanto estiver executando em um serviço real, enquanto a ferramenta de linha de comando é uma boa ajuda para depuração, é um ambiente diferente e não se comporta exatamente como um serviço real.

Nir
fonte
4

Ao desenvolver e depurar um serviço do Windows, normalmente o executo como um aplicativo de console adicionando um parâmetro de inicialização / console e verificando isso. Torna a vida muito mais fácil.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}
Maurice
fonte
Até que você precise depurar problemas específicos do serviço.
Leppie
É verdade que você precisa anexar o depurador ao processo de serviço real. Mas, na maioria dos casos, os erros aparecerão de qualquer maneira e o desenvolvimento é muito mais fácil.
Maurice
4

Que tal Debugger.Break () na primeira linha?

leppie
fonte
2

Para depurar o Windows Services, eu combino o GFlags e um arquivo .reg criado pelo regedit.

  1. Execute o GFlags, especificando o nome do exe e o vsjitdebugger
  2. Execute o regedit e vá para o local em que o GFlags define suas opções
  3. Escolha "Export Key" no menu Arquivo
  4. Salve esse arquivo em algum lugar com a extensão .reg
  5. Sempre que você desejar depurar o serviço: clique duas vezes no arquivo .reg
  6. Se você deseja interromper a depuração, clique duas vezes no segundo arquivo .reg

Ou salve os seguintes trechos e substitua servicename.exe pelo nome do executável desejado.


debugon.reg:

Editor do Registro do Windows versão 5.00

[Opções de execução de arquivo de imagem HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Image \ servicename.exe]
"GlobalFlag" = "0x00000000"
"Depurador" = "vsjitdebugger.exe"

debugoff.reg:

Editor do Registro do Windows versão 5.00

[Opções de execução de arquivo de imagem HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Image \ servicename.exe]
"GlobalFlag" = "0x00000000"

fonte
Isso ainda funciona no Win 7 / Win 2008? É a abordagem de support.microsoft.com/kb/824344, mas depende de serviços interativos e achei que eles foram mortos? Sempre era a minha opção preferida (já que problemas de inicialização podem surgir na produção, onde inserir um Debugger.Break () no código pode não ser uma opção).
usar o seguinte código
1

Para programação de rotina de pequenas coisas, eu fiz um truque muito simples para depurar facilmente meu serviço:

No início do serviço, verifico o parâmetro da linha de comandos "/ debug". Se o serviço for chamado com esse parâmetro, eu não faço a inicialização normal do serviço, mas inicio todos os ouvintes e apenas exibo uma caixa de mensagens "Depuração em andamento, pressione ok para finalizar".

Portanto, se meu serviço for iniciado da maneira usual, ele será iniciado como serviço; se for iniciado com o parâmetro / depuração da linha de comando, ele funcionará como um programa normal.

No VS, adicionarei / deparei como parâmetro de depuração e inicio o programa de serviço diretamente.

Dessa forma, eu posso depurar facilmente para a maioria dos pequenos problemas de tipo. Obviamente, algumas coisas ainda precisarão ser depuradas como serviço, mas para 99% isso é bom o suficiente.

Sam
fonte
1
#if DEBUG
    System.Diagnostics.Debugger.Break();
#endif
Ervin Ter
fonte
1

Eu uso uma variação na resposta da JOP. Usando parâmetros da linha de comando, você pode definir o modo de depuração no IDE com propriedades do projeto ou através do gerenciador de serviços do Windows.

protected override void OnStart(string[] args)
{
  if (args.Contains<string>("DEBUG_SERVICE"))
  {
    Debugger.Break();
  }
  ...
}
nh99
fonte
1

Basta colocar seu almoço do depurador em qualquer lugar e anexar o Visualstudio na inicialização

#if DEBUG
    Debugger.Launch();
#endif

Também é necessário iniciar o VS como Administatrator e permitir que um processo possa ser depurado automaticamente por um usuário diferente (conforme explicado aqui ):

reg add "HKCR\AppID{E62A7A31-6025-408E-87F6-81AEB0DC9347}" /v AppIDFlags /t REG_DWORD /d 8 /f
wotanii
fonte
1

Use o projeto C # do Modelo de Serviço do Windows para criar um novo aplicativo de serviço https://github.com/HarpyWar/windows-service-template

Existem modos de console / serviço detectados automaticamente, instalador / desinstalador automático do seu serviço e vários recursos mais usados ​​estão incluídos.

HarpyWar
fonte
1

Aqui está o método simples que eu usei para testar o serviço, sem métodos adicionais de "Depuração" e com testes de unidade VS integrados.

[TestMethod]
public void TestMyService()
{
    MyService fs = new MyService();

    var OnStart = fs.GetType().BaseType.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

    OnStart.Invoke(fs, new object[] { null });
}

// As an extension method
public static void Start(this ServiceBase service, List<string> parameters)
{
     string[] par = parameters == null ? null : parameters.ToArray();

     var OnStart = service.GetType().GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

     OnStart.Invoke(service, new object[] { par });
}
MisterDr
fonte
1
static class Program
{
    static void Main()
    {
        #if DEBUG

        // TODO: Add code to start application here

        //    //If the mode is in debugging
        //    //create a new service instance
        Service1 myService = new Service1();

        //    //call the start method - this will start the Timer.
        myService.Start();

        //    //Set the Thread to sleep
        Thread.Sleep(300000);

        //    //Call the Stop method-this will stop the Timer.
        myService.Stop();

         #else
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new Service1() 
        };

        ServiceBase.Run(ServicesToRun);
         #endif
    }
}
Mansoor
fonte
isso é mais fácil. basta alterar a configuração da solução para depurar, executar o projeto / solução, adicionar pontos de interrupção à medida que avança.
Bahamut
0

Você tem duas opções para fazer a depuração.

  1. criar um arquivo de log: Pessoalmente, prefiro um arquivo de log separado, como um arquivo de texto, ao invés de usar o log do aplicativo ou o log de eventos.
  2. Converter o aplicativo em aplicativo de console: isso permitirá a você todas as ferramentas de depuração que podemos usar no VS.

Por favor consulte ESTA publicação do blog que eu criei para o tópico.

Sandaru
fonte
0

Basta colar

Debugger.Break();

em qualquer lugar no seu código.

Por exemplo ,

internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        private static void Main()
        {
            Debugger.Break();
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }

Será atingido Debugger.Break();quando você executar o seu programa.

Chutipong Roobklom
fonte
0

A melhor opção é usar o ' System.Diagnostics espaço para nome ' '.

Coloque seu código no bloco if else do modo de depuração e de liberação, como mostrado abaixo, para alternar entre o modo de depuração e de liberação no visual studio,

#if DEBUG  // for debug mode
       **Debugger.Launch();**  //debugger will hit here
       foreach (var job in JobFactory.GetJobs())
            {
                //do something 
            }

#else    // for release mode
      **Debugger.Launch();**  //debugger will hit here
     // write code here to do something in Release mode.

#endif
Amey P Naik
fonte