É possível depurar os serviços do Windows no Visual Studio?
Eu usei código como
System.Diagnostics.Debugger.Break();
mas está apresentando algum erro de código como:
Recebi dois erros de evento: eventID 4096 VsJITDebugger e "O serviço não respondeu à solicitação de início ou controle em tempo hábil."
Você também pode tentar isso.
(Depois de muito pesquisar no Google, encontrei isso em "Como depurar os serviços do Windows no Visual Studio".)
fonte
Você deve separar todo o código que fará as coisas do projeto de serviço em um projeto separado e, em seguida, fazer um aplicativo de teste que possa executar e depurar normalmente.
O projeto de serviço seria apenas o shell necessário para implementar sua parte de serviço.
fonte
Ou isso, conforme sugerido por Lasse V. Karlsen, ou configure um loop em seu serviço que irá aguardar a conexão de um depurador. O mais simples é
while (!Debugger.IsAttached) { Thread.Sleep(1000); } ... continue with code
Dessa forma, você pode iniciar o serviço e dentro do Visual Studio escolher "Anexar ao Processo ..." e anexar ao seu serviço que então irá retomar a execução normal.
fonte
if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Start
/OnStart()
eu achofoo(bar)
Dado que
ServiceBase.OnStart
temprotected
visibilidade, desci a rota de reflexão para conseguir a depuração.private static void Main(string[] args) { var serviceBases = new ServiceBase[] {new Service() /* ... */ }; #if DEBUG if (Environment.UserInteractive) { const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; foreach (var serviceBase in serviceBases) { var serviceType = serviceBase.GetType(); var methodInfo = serviceType.GetMethod("OnStart", bindingFlags); new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase); } return; } #endif ServiceBase.Run(serviceBases); }
Observe que
Thread
é, por padrão, um thread de primeiro plano.return
ing daMain
enquanto os fios de serviço faux estão em execução não vai terminar o processo.fonte
Um artigo da Microsoft explica como depurar um serviço do Windows aqui e que parte alguém pode perder se o depurar anexando a um processo.
Abaixo está meu código de trabalho. Eu segui a abordagem sugerida pela Microsoft.
Adicione este código a
program.cs
:static void Main(string[] args) { // 'If' block will execute when launched through Visual Studio if (Environment.UserInteractive) { ServiceMonitor serviceRequest = new ServiceMonitor(); serviceRequest.TestOnStartAndOnStop(args); } else // This block will execute when code is compiled as a Windows application { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new ServiceMonitor() }; ServiceBase.Run(ServicesToRun); } }
Adicione este código à classe ServiceMonitor.
internal void TestOnStartAndOnStop(string[] args) { this.OnStart(args); Console.ReadLine(); this.OnStop(); }
Agora vá para Propriedades do projeto , selecione a guia "Aplicativo" e selecione Tipo de saída como "Aplicativo de console" ao depurar, ou "Aplicativo do Windows" ao concluir a depuração, recompile e instale seu serviço.
fonte
Você pode fazer um aplicativo de console. Eu uso esta
main
função:static void Main(string[] args) { ImportFileService ws = new ImportFileService(); ws.OnStart(args); while (true) { ConsoleKeyInfo key = System.Console.ReadKey(); if (key.Key == ConsoleKey.Escape) break; } ws.OnStop(); }
Minha
ImportFileService
classe é exatamente a mesma do meu aplicativo de serviço do Windows, exceto o inheritant (ServiceBase
).fonte
ServiceBase
).". Acho mais fácil depurar em um aplicativo de console, mas entendo se isso não convence a todos.Eu uso um ótimo pacote Nuget chamado ServiceProcess.Helpers.
E eu cito ...
Ele ajuda na depuração de serviços do Windows criando uma interface de usuário para reproduzir / parar / pausar ao executar com um depurador conectado, mas também permite que o serviço seja instalado e executado pelo ambiente do servidor Windows.
Tudo isso com uma linha de código.
http://windowsservicehelper.codeplex.com/
Depois de instalado e conectado, tudo o que você precisa fazer é definir seu projeto de serviço do Windows como o projeto de inicialização e clicar em iniciar em seu depurador.
fonte
Você também pode tentar System.Diagnostics.Debugger.Launch () método . Isso ajuda a levar o ponteiro do depurador para o local especificado e você pode depurar o código.
Antes desta etapa , instale seu service.exe usando a linha de comando do prompt de comando do Visual Studio - installutil projectservice.exe
Em seguida, inicie seu serviço no Painel de Controle -> Ferramentas Administrativas -> Gerenciamento do Computador -> Serviço e Aplicativo -> Serviços -> Seu Nome de Serviço
fonte
Acabei de adicionar esse código à minha classe de serviço para que pudesse chamar indiretamente OnStart, semelhante ao OnStop.
public void MyOnStart(string[] args) { OnStart(args); }
fonte
Estou usando o
/Console
parâmetro no projeto Visual Studio Debug → Iniciar Opções → Argumentos da linha de comando :public static class Program { [STAThread] public static void Main(string[] args) { var runMode = args.Contains(@"/Console") ? WindowsService.RunMode.Console : WindowsService.RunMode.WindowsService; new WinodwsService().Run(runMode); } } public class WindowsService : ServiceBase { public enum RunMode { Console, WindowsService } public void Run(RunMode runMode) { if (runMode.Equals(RunMode.Console)) { this.StartService(); Console.WriteLine("Press <ENTER> to stop service..."); Console.ReadLine(); this.StopService(); Console.WriteLine("Press <ENTER> to exit."); Console.ReadLine(); } else if (runMode.Equals(RunMode.WindowsService)) { ServiceBase.Run(new[] { this }); } } protected override void OnStart(string[] args) { StartService(args); } protected override void OnStop() { StopService(); } /// <summary> /// Logic to Start Service /// Public accessibility for running as a console application in Visual Studio debugging experience /// </summary> public virtual void StartService(params string[] args){ ... } /// <summary> /// Logic to Stop Service /// Public accessibility for running as a console application in Visual Studio debugging experience /// </summary> public virtual void StopService() {....} }
fonte
Encontrei esta pergunta, mas acho que falta uma resposta clara e simples.
Não quero anexar meu depurador a um processo, mas ainda quero poder chamar o serviço
OnStart
e osOnStop
métodos. Eu também quero que ele seja executado como um aplicativo de console para que eu possa registrar informações do NLog em um console.Eu encontrei estes guias brilhantes que fazem isso:
Depurando um projeto de serviço do Windows
Maneira mais fácil de depurar um serviço do Windows
Comece alterando os projetos
Output type
paraConsole Application
.Mude seu
Program.cs
para ficar assim:static class Program { /// <summary> /// The main entry point for the application. /// </summary> static void Main() { // Startup as service. ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; if (Environment.UserInteractive) { RunInteractive(ServicesToRun); } else { ServiceBase.Run(ServicesToRun); } } }
Em seguida, adicione o método a seguir para permitir que os serviços sejam executados no modo interativo.
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); }
fonte
Infelizmente, se você estiver tentando depurar algo bem no início de uma operação de serviço do Windows, "anexar" ao processo em execução não funcionará. Tentei usar Debugger.Break () no procedimento OnStart, mas com um aplicativo compilado do Visual Studio 2010 de 64 bits, o comando break apenas gera um erro como este:
System error 1067 has occurred.
Nesse ponto, você precisa configurar uma opção "Execução de arquivo de imagem" no registro para o executável. Leva cinco minutos para configurar e funciona muito bem. Aqui está um artigo da Microsoft onde os detalhes são:
Como: iniciar o depurador automaticamente
fonte
Experimente a linha de comando de pós-construção do próprio Visual Studio .
Tente adicionar isso na pós-construção:
@echo off sc query "ServiceName" > nul if errorlevel 1060 goto install goto stop :delete echo delete sc delete "ServiceName" > nul echo %errorlevel% goto install :install echo install sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul echo %errorlevel% goto start :start echo start sc start "ServiceName" > nul echo %errorlevel% goto end :stop echo stop sc stop "ServiceName" > nul echo %errorlevel% goto delete :end
Se o erro de compilação com uma mensagem como esta
Error 1 The command "@echo off sc query "ServiceName" > nul
por diante, Ctrl+ Centão Ctrl+ Va mensagem de erro no Bloco de Notas e observe a última frase da mensagem.Pode ser dizer
exited with code x
. Procure o código de algum erro comum aqui e veja como resolvê-lo.1072 -- Marked for deletion → Close all applications that maybe using the service including services.msc and Windows event log. 1058 -- Can't be started because disabled or has no enabled associated devices → just delete it. 1060 -- Doesn't exist → just delete it. 1062 -- Has not been started → just delete it. 1053 -- Didn't respond to start or control → see event log (if logged to event log). It may be the service itself throwing an exception. 1056 -- Service is already running → stop the service, and then delete.
Mais sobre códigos de erro aqui .
E se o erro de compilação com mensagem como esta,
Error 11 Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed. ServiceName Error 12 Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process. ServiceName
abra o cmd e tente matá-lo primeiro com
taskkill /fi "services eq ServiceName" /f
Se tudo estiver bem, F5deve ser suficiente para depurá-lo.
fonte
No
OnStart
método, faça o seguinte.protected override void OnStart(string[] args) { try { RequestAdditionalTime(600000); System.Diagnostics.Debugger.Launch(); // Put breakpoint here. .... Your code } catch (Exception ex) { .... Your exception code } }
Em seguida, execute um prompt de comando como administrador e insira o seguinte:
A linha acima criará test-xyzService na lista de serviços.
Para iniciar o serviço, isso solicitará que você anexe a estreia no Visual Studio ou não.
Para parar o serviço:
Para excluir ou desinstalar:
fonte
Depure um serviço do Windows em http (testado com VS 2015 Atualização 3 e .Net FW 4.6)
Em primeiro lugar, você deve criar um projeto de console dentro de sua solução VS (Adicionar -> Novo projeto -> Aplicativo de console).
Dentro do novo projeto, crie uma classe "ConsoleHost" com esse código:
class ConsoleHost : IDisposable { public static Uri BaseAddress = new Uri(http://localhost:8161/MyService/mex); private ServiceHost host; public void Start(Uri baseAddress) { if (host != null) return; host = new ServiceHost(typeof(MyService), baseAddress ?? BaseAddress); //binding var binding = new BasicHttpBinding() { Name = "MyService", MessageEncoding = WSMessageEncoding.Text, TextEncoding = Encoding.UTF8, MaxBufferPoolSize = 2147483647, MaxBufferSize = 2147483647, MaxReceivedMessageSize = 2147483647 }; host.Description.Endpoints.Clear(); host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress ?? BaseAddress); // Enable metadata publishing. var smb = new ServiceMetadataBehavior { HttpGetEnabled = true, MetadataExporter = { PolicyVersion = PolicyVersion.Policy15 }, }; host.Description.Behaviors.Add(smb); var defaultBehaviour = host.Description.Behaviors.OfType<ServiceDebugBehavior>().FirstOrDefault(); if (defaultBehaviour != null) { defaultBehaviour.IncludeExceptionDetailInFaults = true; } host.Open(); } public void Stop() { if (host == null) return; host.Close(); host = null; } public void Dispose() { this.Stop(); } }
E este é o código para a classe Program.cs:
public static class Program { [STAThread] public static void Main(string[] args) { var baseAddress = new Uri(http://localhost:8161/MyService); var host = new ConsoleHost(); host.Start(null); Console.WriteLine("The service is ready at {0}", baseAddress); Console.WriteLine("Press <Enter> to stop the service."); Console.ReadLine(); host.Stop(); } }
Configurações como as cadeias de conexão devem ser copiadas no arquivo App.config do projeto do console.
Para fortalecer o console, clique com o botão direito do mouse no projeto do console e clique em Depurar -> Iniciar nova instância.
fonte
Basta adicionar um construtor à sua classe de serviço (se ainda não o tiver). Abaixo, você pode verificar um exemplo para o .net visual basic.
Public Sub New() OnStart(Nothing) End Sub
Depois disso, clique com o botão direito do mouse no projeto e selecione " Debug -> Iniciar uma nova instância ".
fonte