J'ai du code écrit en .NET qui échoue uniquement lorsqu'il est installé en tant que service Windows. L'échec ne permet même pas au service de démarrer. Je ne peux pas comprendre comment je peux entrer dans la méthode OnStart.
Comment: déboguer les applications de service Windows donne un indice alléchant:
L'attachement au processus du service vous permet de déboguer la plupart mais pas la totalité du code du service; par exemple, parce que le service a déjà été démarré, vous ne pouvez pas déboguer le code dans la méthode OnStart du service de cette façon, ou le code dans la méthode Main qui est utilisé pour charger le service. Une façon de contourner ce problème consiste à créer un deuxième service temporaire dans votre application de service qui existe uniquement pour faciliter le débogage. Vous pouvez installer les deux services, puis démarrer ce service "factice" pour charger le processus de service. Une fois que le service temporaire a démarré le processus, vous pouvez ensuite utiliser le menu Déboguer dans Visual Studio pour attacher au processus de service.
Cependant, je ne sais pas exactement comment vous êtes censé créer le service factice pour charger le processus de service.
Une chose que vous pouvez faire comme solution de contournement temporaire est de lancer le débogueur comme première ligne de code dans OnStart
System.Diagnostics.Debugger.Launch()
Cela vous demandera le débogueur que vous souhaitez utiliser. Ayez simplement la solution déjà ouverte dans Visual Studio et choisissez cette instance dans la liste.
J'ai tendance à ajouter une méthode comme celle-ci:
[Conditional("DEBUG")]
private void AttachDebugger()
{
Debugger.Break();
}
il ne sera appelé que sur les versions de débogage de votre projet et il suspendra l'exécution et vous permettra d'attacher le débogueur.
Une fois que vous avez un service installé à l'aide de installutil.exe
, Vous pouvez modifier le Start Parameters
Pour accéder au débogueur si le service est démarré:
Lorsque vous démarrez manuellement le service avec le paramètre -debugWithVisualStudio
(Ou simplement -d
), Il détectera automatiquement le projet correct et lancera le débogueur interactif dans Visual Studio:
Pour prendre en charge cette fonctionnalité, modifiez la fonction OnStart()
du service:
/// <summary>
/// Executed when the service is started.
/// </summary>
/// <param name="args">Command line arguments.</param>
protected override void OnStart(string[] args)
{
try
{
//How to debug when running a Windows Service:
// 1. Right click on the service name in Windows Service Manager.
// 2. Select "Properties".
// 3. In "Start Parameters", enter "-d" (or "-debugWithVisualStudio").
// 4. Now, when you start the service, it will fire up Visual Studio 2012 and break on the line below.
// 5. Make sure you have UAC (User Access Control) turned off, and have Administrator privileges.
#if DEBUG
if (((ICollection<string>)args).Contains("-d")
|| ((ICollection<string>)args).Contains("-debugWithVisualStudio"))
{
Debugger.Launch(); // Launches VS2012 debugger.
}
#endif
ShellStart(args);
base.OnStart(args);
}
catch (Exception ex)
{
// Log exception here.
}
}
(facultatif) Si vous souhaitez réduire la ligne de code exacte où le service génère une erreur, activez les exceptions dans le menu Visual Studio DEBUG .. Exceptions
. Lorsque vous continuez le débogage, il s'arrête sur la ligne exacte qui lève l'exception.
Cela fonctionne très bien!
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
}
Les options ci-dessus ne semblent pas fonctionner sous Windows 8.
J'ai ajouté Thread.Sleep (15000); dans ma méthode OnStart () et définir un point d'arrêt sur la ligne suivante du code. Cela me donne 15 secondes pour attacher le débogueur VS à mon processus après le démarrage du service et m'a permis de déboguer correctement la méthode OnStart ().
Vous pouvez ajouter une ligne de code comme celle-ci:
System.Diagnostics.Debugger.Break()
qui fera apparaître une fenêtre vous invitant à choisir le débogueur à utiliser pour déboguer, par exemple vous permettant de vous attacher avec Visual Studio et d'entrer dans le code.
voir:
http://msdn.Microsoft.com/en-us/library/system.diagnostics.debugger.break.aspx
Comme d'autres l'ont souligné, vous devez ajouter un saut de débogueur à la méthode OnStart:
#if DEBUG
System.Diagnostics.Debugger.Break()
#endif
Démarrez également VisualStudio en tant qu'administrateur et autorisez qu'un processus puisse être débogué automatiquement par un autre utilisateur (comme expliqué ici ):
reg add "HKCR\AppID\{E62A7A31-6025-408E-87F6-81AEB0DC9347}" /v AppIDFlags /t REG_DWORD /d 8 /f
(J'ai également expliqué cela ici: https://stackoverflow.com/a/35715389/5132456 )
Utilisez le code suivant dans la méthode Service OnStart:
System.Diagnostics.Debugger.Launch();
Choisissez l'option Visual Studio dans le message contextuel. N'oubliez pas d'exécuter Visual Studio en tant qu'administrateur.
Remarque: Pour l'utiliser en mode débogage uniquement, la directive du compilateur #if DEBUG peut être utilisée, comme suit. Cela empêchera tout accident ou débogage en mode Release sur le serveur de production.
#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif
Il est possible de configurer un projet compagnon pour le service Windows qui s'exécute comme une application console, mais accède aux méthodes de service à l'aide de Reflection. Voir ici pour plus de détails et un exemple: http://ryan.kohn.ca/articles/how-to-debug-a-windows-service-in-csharp-using-reflection/ .
Je sais que c'est en retard, mais c'est ainsi que nous gérons le débogage des services Windows
Créez d'abord une classe qui servira de service.
Ajoutez les méthodes appropriées pour démarrer, arrêter, mettre en pause, etc ...
Ajoutez un formulaire Windows au projet de service.
Dans le code de service, créez la classe de service créée ci-dessus et effectuez les appels nécessaires pour démarrer et arrêter le service dans la classe ServiceBase
Ouvrez le Program.cs et ajoutez ce qui suit
#if DEBUG
[STAThread]
#endif
static void Main()
{
try
{
#if DEBUG
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new DebugForm());
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new YourWindowsService()
};
ServiceBase.Run(ServicesToRun);
#endif
}
catch (Exception e)
{
logger.Error(DateTime.Now.ToString() + " - " + e.Source + " - " + e.ToString() + "\r\n------------------------------------\r\n");
}
}
Lorsque vous exécutez en mode DEBUG, le formulaire Windows se lance. N'oubliez pas de construire en mode Release lorsque vous avez terminé. Bien sûr, la variable de compilation conditionnelle peut être ce que vous voulez. Vous pouvez même créer des projets séparés afin que le formulaire de débogage soit son propre projet.
J'espère que cela t'aides
Vous pouvez également essayer la méthode System.Diagnostics.Debugger.Launch (). Il 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 commandes de 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
Si vous ajoutez Debugger.Launch () dans votre méthode OnStart et que cela ne fonctionne pas, vous pourriez avoir le même problème que moi, à savoir que l'exception se produisait dans le constructeur, donc OnStart n'a jamais été appelé. (claque de tête)
(désolé si cela aurait dû être un commentaire sur la réponse de quelqu'un d'autre, mais je n'ai pas assez de crédit pour faire des commentaires)
Essayez d'ajouter Debugger.Break à l'intérieur de la méthode problématique. Lorsque le service démarrera, une exception sera levée et les veuves devraient proposer de le déboguer à l'aide de Visual Studio.
J'ai généralement une application console qui prétend être le SCM, par exemple appelle Start, Stop dans lequel je peux ensuite simplement F5 pour mes principaux objectifs de codage/débogage, et utiliser le Debugger.Break pour le débogage lorsque le service a été installé et démarré via le SCM.
Cela signifie un peu plus de travail pour commencer, j'ai une bibliothèque de classe qui contient tout le code de service, avec une classe qui expose Start et Stop que la classe Service Windows et l'application console peuvent appeler.
Mat
Avant d'entrer dans le sujet, on vous conseille. Utilisez toujours le journal spécialement si vous êtes développeur côté serveur. Parce qu'il existe certaines conditions que vous ne pourrez peut-être pas produire lors du débogage du code dans Visual Studio.
Pour en revenir au sujet, j'utilise Envoirnment.UserInteractive flag c'est vraiment pratique voir mon code ci-dessous
public static void Main(string[] args)
{
if (System.Environment.UserInteractive)
{
string parameter = string.Concat(args);
switch (parameter)
{
case "--install":
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
break;
case "--uninstall":
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
break;
default:
WindowsService service = new WindowsService();
service.OnStart(args);
Console.ReadKey();
service.OnStop();
break;
}
}
else
{
ServiceBase.Run(new WindowsService());
}
}
À partir de Visual Studio, vous obtiendrez un indicateur UserInteractive afin que je l'exécute en tant qu'application console.En plus de cela, vous pouvez également exécuter la génération de produit en double-cliquant dessus et en y attachant le débogueur si vous souhaitez le tester.
J'ai une façon intéressante de le faire j'ajoute une autre configuration appelée DebugNoService
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugNoService|AnyCPU' ">
<OutputPath>.\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE;DEBUGNOSERVICE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>Prompt</ErrorReport>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
J'utilise la directive #if. ProjectInstaller.cs
#if !DEBUGNOSERVICE
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
.....
}
#endif
J'ajoute un formulaire Windows et j'enveloppe également le formulaire Windows dans
#if DEBUGNOSERVICE
...
static void Main()
{
Form form;
Application.EnableVisualStyles();
Application.DoEvents();
form = new <the name of the form>();
Application.Run(form);
}
...
#endif
en fonction de la configuration sélectionnée, le code s'exécute soit comme une application Windows Form qui peut être facilement déboguée, soit comme un service.
Cela semble beaucoup de travail, mais cela a toujours fonctionné et rend le débogage du code très très facile. Vous pouvez ajouter toutes sortes de sorties au formulaire afin de pouvoir le regarder s'exécuter.