web-dev-qa-db-fra.com

Comment déboguer la méthode OnStart du service Windows .NET?

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.

52
Nathan

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.

96
palehorse

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.

10
SpaceghostAli

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é:

enter image description here

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:

enter image description here

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.

enter image description here

8
Contango

Cela fonctionne très bien!

protected override void OnStart(string[] args)
{
    System.Diagnostics.Debugger.Launch();
}
7
Developer

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 ().

5
Boris Hurinek

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

4
Alex Black

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 )

2
wotanii

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
2
Chirag

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/ .

2
Ryan Kohn

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

1
Coach David

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

1

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)

1
and... break

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.

0
Dror Helper

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

0
Matt

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.

0
Mubashar

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.

0
M pollack