Est-il possible de déboguer les services Windows dans Visual Studio?
J'ai utilisé du code comme
System.Diagnostics.Debugger.Break();
mais cela donne une erreur de code comme:
J'ai eu deux erreurs d'événement: eventID 4096 VsJITDebugger et "Le service n'a pas répondu à la demande de démarrage ou de contrôle en temps opportun."
Vous pouvez également essayer ceci.
(Après de nombreuses recherches sur Google, j'ai trouvé ceci dans "Comment déboguer les services Windows dans Visual Studio".)
la source
Vous devez séparer tout le code qui ne choses du projet de service dans un projet distinct, puis faire une application de test que vous pouvez exécuter et déboguer normalement.
Le projet de service ne serait que le shell nécessaire pour implémenter la partie service de celui-ci.
la source
Soit cela comme suggéré par Lasse V. Karlsen, soit mettre en place une boucle dans votre service qui attendra qu'un débogueur se connecte. Le plus simple est
while (!Debugger.IsAttached) { Thread.Sleep(1000); } ... continue with code
De cette façon, vous pouvez démarrer le service et à l'intérieur de Visual Studio, vous choisissez «Attach to Process ...» et attachez-vous à votre service qui reprendra alors l'exécution normale.
la source
if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Start
/OnStart()
Je supposefoo(bar)
Étant donné que cela
ServiceBase.OnStart
a de laprotected
visibilité, j'ai emprunté la voie de la réflexion pour effectuer le débogage.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); }
Notez qu'il
Thread
s'agit, par défaut, d'un fil de discussion au premier plan.return
le faitMain
que les threads de faux-service s'exécutent ne mettra pas fin au processus.la source
Un article Microsoft explique comment déboguer un service Windows ici et quelle partie n'importe qui peut manquer s'il le débogage en se connectant à un processus.
Voici mon code de travail. J'ai suivi l'approche suggérée par Microsoft.
Ajoutez ce code à
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); } }
Ajoutez ce code à la classe ServiceMonitor.
internal void TestOnStartAndOnStop(string[] args) { this.OnStart(args); Console.ReadLine(); this.OnStop(); }
Maintenant, allez dans Propriétés du projet , sélectionnez l'onglet "Application" et sélectionnez Type de sortie comme "Application console" lors du débogage, ou "Application Windows" lorsque vous avez terminé le débogage, recompilez et installez votre service.
la source
Vous pouvez créer une application console. J'utilise cette
main
fonction: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(); }
Ma
ImportFileService
classe est exactement la même que dans l'application de mon service Windows, à l'exception de l'héritante (ServiceBase
).la source
ServiceBase
).". Je trouve plus facile de déboguer dans une application console, mais je comprends si cela ne convainc pas tout le monde.J'utilise un excellent package Nuget appelé ServiceProcess.Helpers.
Et je cite ...
Il aide le débogage des services Windows en créant une interface utilisateur lecture / arrêt / pause lors de l'exécution avec un débogueur attaché, mais permet également au service d'être installé et exécuté par l'environnement de serveur Windows.
Tout cela avec une seule ligne de code.
http://windowsservicehelper.codeplex.com/
Une fois installé et câblé, tout ce que vous avez à faire est de définir votre projet de service Windows comme projet de démarrage et de cliquer sur démarrer sur votre débogueur.
la source
Vous pouvez également essayer la méthode System.Diagnostics.Debugger.Launch () . Cela aide à amener le pointeur du débogueur à l'emplacement spécifié et vous pouvez ensuite déboguer votre code.
Avant cette étape, veuillez installer votre service.exe à l'aide de la ligne de commande de l'invite de commande Visual Studio - installutil projectservice.exe
Ensuite, démarrez votre service à partir du Panneau de configuration -> Outils d'administration -> Gestion de l'ordinateur -> Service et application -> Services -> Votre nom de service
la source
Je viens d'ajouter ce code à ma classe de service pour pouvoir appeler indirectement OnStart, similaire pour OnStop.
public void MyOnStart(string[] args) { OnStart(args); }
la source
J'utilise le
/Console
paramètre dans le projet Visual Studio Debug → Options de démarrage → Arguments de ligne de commande :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() {....} }
la source
J'ai trouvé cette question, mais je pense qu'il manque une réponse claire et simple.
Je ne veux pas attacher mon débogueur à un processus, mais je veux toujours pouvoir appeler le service
OnStart
et lesOnStop
méthodes. Je veux également qu'il s'exécute en tant qu'application console afin que je puisse enregistrer les informations de NLog vers une console.J'ai trouvé ces guides brillants qui font cela:
Débogage d'un projet de service Windows
Un moyen plus simple de déboguer un service Windows
Commencez par changer les projets
Output type
enConsole Application
.Changez votre
Program.cs
pour ressembler à ceci: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); } } }
Ajoutez ensuite la méthode suivante pour autoriser les services s'exécutant en mode interactif.
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); }
la source
Malheureusement, si vous essayez de déboguer quelque chose au tout début d'une opération de service Windows, la "connexion" au processus en cours ne fonctionnera pas. J'ai essayé d'utiliser Debugger.Break () dans la procédure OnStart, mais avec une application compilée Visual Studio 2010 64 bits, la commande break lève simplement une erreur comme celle-ci:
System error 1067 has occurred.
À ce stade, vous devez configurer une option «Exécution de fichier image» dans votre registre pour votre exécutable. La configuration prend cinq minutes et fonctionne très bien. Voici un article Microsoft dont les détails sont:
Comment: lancer le débogueur automatiquement
la source
Essayez la ligne de commande d'événement post-build de Visual Studio .
Essayez d'ajouter ceci dans la post-construction:
@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
Si l'erreur de construction avec un message comme celui-ci
Error 1 The command "@echo off sc query "ServiceName" > nul
, Ctrl+ Cpuis Ctrl+ Vle message d'erreur dans le Bloc-notes et regardez la dernière phrase du message.Ça pourrait être dire
exited with code x
. Recherchez le code dans une erreur courante ici et voyez comment le résoudre.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.
Plus d'informations sur les codes d'erreur ici .
Et si l'erreur de construction avec un message comme celui-ci,
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
ouvrez cmd, puis essayez de le tuer d'abord avec
taskkill /fi "services eq ServiceName" /f
Si tout va bien, cela F5devrait suffire à le déboguer.
la source
Dans la
OnStart
méthode, procédez comme suit.protected override void OnStart(string[] args) { try { RequestAdditionalTime(600000); System.Diagnostics.Debugger.Launch(); // Put breakpoint here. .... Your code } catch (Exception ex) { .... Your exception code } }
Ensuite, exécutez une invite de commande en tant qu'administrateur et entrez ce qui suit:
La ligne ci-dessus créera test-xyzService dans la liste des services.
Pour démarrer le service, cela vous demandera de vous attacher pour faire ses débuts dans Visual Studio ou non.
Pour arrêter le service:
Pour supprimer ou désinstaller:
la source
Déboguer un service Windows sur http (testé avec VS 2015 Update 3 et .Net FW 4.6)
Tout d'abord, vous devez créer un projet de console dans votre solution VS (Ajouter -> Nouveau projet -> Application console).
Dans le nouveau projet, créez une classe "ConsoleHost" avec ce code:
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(); } }
Et voici le code de la 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(); } }
Les configurations telles que les chaînes de connexion doivent être copiées dans le fichier App.config du projet Console.
Pour renforcer la console, cliquez avec le bouton droit sur le projet de console et cliquez sur Déboguer -> Démarrer une nouvelle instance.
la source
Ajoutez simplement un constructeur à votre classe de service (si vous ne l'avez pas déjà). Ci-dessous, vous pouvez consulter un exemple pour Visual Basic .net.
Public Sub New() OnStart(Nothing) End Sub
Ensuite, faites un clic droit sur le projet et sélectionnez " Déboguer -> Démarrer une nouvelle instance ".
la source