La forma más fácil de depurar un servicio de Windows

Respuestas:

271

Si quiero depurar rápidamente el servicio, simplemente entro Debugger.Break()allí. Cuando se alcanza esa línea, me devolverá a VS. No olvide eliminar esa línea cuando haya terminado.

ACTUALIZACIÓN: Como alternativa a los #if DEBUGpragmas, también puede usar el Conditional("DEBUG_SERVICE")atributo.

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

En su OnStart, simplemente llame a este método:

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

Allí, el código solo se habilitará durante las compilaciones de depuración. Mientras lo hace, puede ser útil crear una configuración de compilación separada para la depuración del servicio.

jop
fuente
45
O puede usar Debugger.Launch () deberá incluir una declaración de uso para el espacio de nombres The Systems.Diagnostics.
Omar Kooheji
1
Su publicación en el blog funcionó bien y me salvó el día :) sin embargo, el Debugger.Break () no funcionó para mí. parece que .Net omite la función DebugMode por algunas razones relacionadas con la optimización.
Bizhan
3
Debugger.Launch () funciona para mí cuando Debugger.Break () no lo hace. (El proceso sale con el código 255.)
Oliver Bock
¿Cómo están haciendo que esto funcione? No pasa nada. He intentado Break () y Launch ().
4thSpace
13
@ 4thSpace: 1. cree un instalador para su servicio, para que pueda instalar su servicio. 2. Agregue la línea Debugger.Launch (); al comienzo de tu Main (). 3. Cree su código en modo de depuración. 4. Sobrescriba los dll instalados con los debll-dll. 5. Inicie el servicio desde el panel de Servicios de Windows. Ahora aparece una ventana emergente que le pide que se adjunte a un depurador. De esta manera funcionó para mí. Ojalá para ti también.
ffonz
210

También creo que tener una "versión" separada para la ejecución normal y como servicio es el camino a seguir, pero ¿es realmente necesario dedicar un interruptor de línea de comando separado para ese propósito?

¿No podrías simplemente hacer:

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

Eso tendría el "beneficio" de que puede iniciar su aplicación mediante un doble clic (OK, si realmente lo necesita) y que puede presionar F5en Visual Studio (sin la necesidad de modificar la configuración del proyecto para incluir esa /consoleOpción).

Técnicamente, Environment.UserInteractivecomprueba si el WSF_VISIBLEindicador está configurado para la estación de ventana actual, pero ¿hay alguna otra razón por la que regresaría false, además de ejecutarse como un servicio (no interactivo)?

Christian.K
fuente
¡Excelente! Anteriormente utilicé un método "if #debug" para iniciar como aplicación en caso de depuración, de lo contrario, un servicio. Esto lleva a que la aplicación no se pueda ejecutar como un servicio si desea depurarla, pero su solución lo resuelve y permite que se pueda ejecutar en las cuatro combinaciones de servicio / aplicación y lanzamiento / depuración.
Jonas
29
Si no desea que el programa se ejecute cuando se hace doble clic (los usuarios pueden confundirse y ejecutar varias instancias, etc.), puede usarlo en System.Diagnostics.Debugger.IsAttachedlugar de hacerlo Environment.UserInteractive.
Blorgbeard sale
55
pero ¿hay alguna otra razón por la que devolvería falso, además de ejecutarse como un servicio (no interactivo)? Puedo pensar en uno: una tarea programada que no se adjunta a una consola.
Hogan
77
Yo uso los parámetros de línea de comando para este caso. --instalar para instalar el servicio, - desinstalar para desinstalar el servicio y --interactivo para ejecutar el servicio como aplicación. agrego --interactivo a las opciones del proyecto (Depuración> Argumentos de comando). Entonces puedo depurar fácilmente desde VS. hacer doble clic no creará una instancia de ejecución no deseada ya que se requiere interacción. solo mis 2 centavos.
Emir Akaydın
@ EmirAkaydın Sí, en realidad también tengo parámetros de línea de comando como "copia de seguridad". Sin embargo, en realidad quería tener una instancia "interactiva" al hacer doble clic y no y un mensaje de error sobre el hecho de que un servicio no se puede iniciar de esa manera. Varias metas, supongo ;-)
Christian.K
123

Cuando configuré un nuevo proyecto de servicio hace unas semanas, encontré esta publicación. Si bien hay muchas sugerencias geniales, todavía no encontré la solución que quería: la posibilidad de llamar a las clases OnStarty OnStopmétodos de servicio sin ninguna modificación a las clases de servicio.

La solución que se me ocurrió utiliza el Environment.Interactivemodo de ejecución selectivo, como lo sugieren otras respuestas a esta publicación.

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

El RunInteractiveayudante usa la reflexión para llamar a los métodos OnStarty protegidos 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 es todo el código requerido, pero también escribí un tutorial con explicaciones.

Anders Abel
fuente
Esto hace un buen método de extensión para ServiceBase []. Tengo múltiples servicios en mi solución, así que en lugar de tener una clase base común para Program.cs, solo llamo servicesToRun.RunInteractive (args). ¡Buena solución @Anders!
David Keaveny
3
Gran solución de hecho. Creé una extensión simple para ServiceBase [] como sugirió David, que permite ejecutar servicios en una sola línea de código: pastebin.com/F0fhhG2R
Funbit
44
+1 Un antiguo colega mío creó una clase base "EasyRunService" (que hereda ServiceProcess) que hace más o menos lo mismo, pero sin necesidad de reflexión (porque OnStart ahora está en la clase base). Realmente hace que depurar un servicio de Windows sea muy fácil.
sondergard
3
@ Chazt3n Asegúrese de que el tipo de salida de su proyecto esté configurado en "Aplicación de consola". En cuanto a la instalación del servicio, no importa qué tipo de salida se seleccione, el comportamiento es el mismo.
Funbit
2
Sigue siendo una gran solución! Lo único que agregaría (como se muestra en el walk through) es asegurarme de que vaya a las propiedades del proyecto y cambie el tipo de salida a Console Applicationantes de intentar compilar y ejecutar. Encuéntralo en Project Properties -> Application -> Output type -> Console Application. Además, para que esto funcione correctamente para mí, terminé teniendo que ejecutar la aplicación usando el startcomando. Ej: C:\"my app name.exe" -serviceno funcionaría para mí. En cambio, solíaC:\start /wait "" "my app name.exe" -service
Arvo Bowen el
47

A veces es importante analizar lo que sucede durante el inicio del servicio. Adjuntar al proceso no ayuda aquí, porque no es lo suficientemente rápido como para adjuntar el depurador mientras se inicia el servicio.

La respuesta corta es que estoy usando las siguientes 4 líneas de código para hacer esto:

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

Estos se insertan en el OnStartmétodo del servicio de la siguiente manera:

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 aquellos que no lo han hecho antes, he incluido consejos detallados a continuación , porque pueden atascarse fácilmente. Las siguientes sugerencias se refieren a Windows 7x64 y Visual Studio 2010 Team Edition , pero también deberían ser válidas para otros entornos.


Importante: Implemente el servicio en modo "manual" (utilizando la InstallUtilutilidad desde el símbolo del sistema VS o ejecute un proyecto de instalador de servicio que haya preparado). Abra Visual Studio antes de iniciar el servicio y cargue la solución que contiene el código fuente del servicio, configure puntos de interrupción adicionales según lo requiera en Visual Studio, luego inicie el servicio a través del Panel de control del servicio.

Debido al Debugger.Launchcódigo, esto generará un cuadro de diálogo "Se produjo una excepción no controlada de Microsoft .NET Framework en Servicename.exe ". a aparecer. Haga clic como se muestra en la captura de pantalla:Elevate Yes, debug Servicename.exe
FrameworkException

Posteriormente, especialmente en Windows 7 UAC puede solicitarle que ingrese las credenciales de administrador. Ingrese y proceda con Yes:

UACPrompt

Después de eso, aparece la conocida ventana del depurador Just-In-Time de Visual Studio . Le pregunta si desea depurar utilizando el depurador eliminado. Antes de hacer clic Yes, seleccione que no desea abrir una nueva instancia (segunda opción); una nueva instancia no sería útil aquí, porque el código fuente no se mostraría. Entonces, seleccione la instancia de Visual Studio que abrió anteriormente: VSDebuggerPrompt

Después de hacer clic Yes, Visual Studio mostrará la flecha amarilla justo en la línea donde está la Debugger.Launchinstrucción y podrá depurar su código (método MyInitOnStart, que contiene su inicialización). VSDebuggerBreakpoint

Al presionar F5continúa la ejecución de inmediato, hasta que se alcanza el siguiente punto de interrupción que ha preparado.

Sugerencia: para mantener el servicio en funcionamiento, seleccione Depurar -> Separar todo . Esto le permite ejecutar un cliente que se comunica con el servicio después de que se haya iniciado correctamente y haya terminado de depurar el código de inicio. Si presiona Shift+F5 (detener la depuración), esto terminará el servicio. En lugar de hacer esto, debe usar el Panel de control de servicio para detenerlo.

Tenga en cuenta que

  • Si crea una versión, el código de depuración se elimina automáticamente y el servicio se ejecuta normalmente.

  • Estoy usando Debugger.Launch(), que inicia y adjunta un depurador . También lo probé Debugger.Break(), lo que no funcionó , porque todavía no hay un depurador conectado al iniciar el servicio (causando el "Error 1067: El proceso finalizó inesperadamente" ).

  • RequestAdditionalTimeestablece un largo tiempo de espera para el inicio del servicio (se no retrasar el código en sí mismo, sino que continuará inmediatamente con la Debugger.Launchdeclaración). De lo contrario, el tiempo de espera predeterminado para iniciar el servicio es demasiado corto y el servicio falla si no llama base.Onstart(args)lo suficientemente rápido desde el depurador. Prácticamente, un tiempo de espera de 10 minutos evita que vea el mensaje " el servicio no respondió ..." inmediatamente después de que se inicia el depurador.

  • Una vez que te acostumbras, este método es muy fácil porque solo requiere que agregues 4 líneas a un código de servicio existente, lo que te permite obtener rápidamente control y depuración.

Mate
fuente
1
Por curiosidad, ¿sabe si hay un tiempo de espera para la interacción del usuario con el indicador de usuario Debugger.Launch ()?
Shiv
1
Como se describe, base.RequestAdditionalTime(600000)evitará que el control del servicio termine el servicio durante 10 minutos si no llama base.OnStart(args)dentro de ese intervalo de tiempo). Aparte de eso, recuerdo que UAC también abortará si no ingresa las credenciales de administrador después de un tiempo (no sé cuántos segundos exactamente, pero creo que debe ingresarlo en un minuto, de lo contrario, UAC cancela) , que finalizará la sesión de depuración.
Matt
2
Encontré que este es el mejor método para depurar mensajes CustomCommand. +1.
Justin
40

Lo que generalmente hago es encapsular la lógica del servicio en una clase separada y comenzar eso desde una clase 'runner'. Esta clase de corredor puede ser el servicio real o simplemente una aplicación de consola. Entonces su solución tiene (al menos) 3 proyectos:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....
Paul van Brenk
fuente
1
Solía ​​usar este enfoque también, pero creo que una combinación de esto y la respuesta anterior funciona de maravilla.
RobS
27

Este video de YouTube de Fabio Scopel explica cómo depurar un servicio de Windows bastante bien ... el método real de hacerlo comienza a las 4:45 en el video ...

Aquí está el código explicado en el video ... en su archivo Program.cs, agregue las cosas para la sección de Depuración ...

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

        }
    }
}

En su archivo Service1.cs, agregue el 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()
    {
    }

Cómo funciona

Básicamente, debe crear un public void OnDebug()que llame al OnStart(string[] args)ya que está protegido y no es accesible desde el exterior. El void Main()programa se agrega con #ifpreprocesador con #DEBUG.

Visual Studio define DEBUGsi el proyecto se compila en modo de depuración. Esto permitirá que la sección de depuración (a continuación) se ejecute cuando la condición sea verdadera

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

Y se ejecutará como una aplicación de consola, una vez que las cosas salgan bien, puede cambiar el modo Releasey la elsesección normal activará la lógica

Jason Miller
fuente
Estaba buscando esta respuesta, no sé por qué estaba clasificada tan baja. Explicó el código para ayudar a otros o posiblemente más comentarios;)
Vinod Srivastav
14

ACTUALIZAR

Este enfoque es, con mucho, el más fácil:

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

Dejo mi respuesta original a continuación para la posteridad.


Mis servicios tienden a tener una clase que encapsula un temporizador, ya que quiero que el servicio verifique a intervalos regulares si hay algún trabajo que hacer.

Actualizamos la clase y llamamos a StartEventLoop () durante el inicio del servicio. (Esta clase también podría usarse fácilmente desde una aplicación de consola).

El agradable efecto secundario de este diseño es que los argumentos con los que configura el temporizador se pueden usar para tener un retraso antes de que el servicio realmente comience a funcionar, de modo que tenga tiempo para adjuntar un depurador manualmente.

ps ¿Cómo adjuntar el depurador manualmente a un proceso en ejecución ...?

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");
    }
}

También solía hacer lo siguiente (ya se mencionó en respuestas anteriores pero con los indicadores del compilador condicional [#if] para ayudar a evitar que se active en una versión de lanzamiento).

Dejé de hacerlo de esta manera porque a veces nos olvidamos de compilar en Release y tener una interrupción del depurador en una aplicación que se ejecuta en una demostración de cliente (¡vergonzoso!).

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif
rohancragg
fuente
¿Qué sucede cuando // do somethingtarda más de 30 minutos en completarse?
Vinod Srivastav
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
fuente
[Perdón por no haber explicaciones con el código - problemas de rebajas] Debería ejecutarse normalmente desde MS Visual Studio (F5) en versiones de depuración. Todavía se ejecuta como un servicio normal en las versiones de lanzamiento.
Thomas Bratt
Combine esto con la solución anterior de Christian K. para usar la propiedad "Environment.UserInteractive" y la solución es realmente limpia y simple.
Ben Robbins
OnStartes protectedy no puedes modificar el nivel de acceso :(
Eduard Luca
10

También puede iniciar el servicio a través del símbolo del sistema (sc.exe).

Personalmente, ejecutaría el código como un programa independiente en la fase de depuración, y cuando se solucionen la mayoría de los errores, cambiaría a ejecutar como servicio.

akauppi
fuente
10

Lo que solía hacer era tener un interruptor de línea de comando que iniciara el programa como un servicio o como una aplicación normal. Luego, en mi IDE, configuraría el interruptor para poder pasar por mi código.

Con algunos idiomas, puede detectar si se está ejecutando en un IDE y realizar este cambio automáticamente.

Qué idioma estás usando?

RB.
fuente
9

Use la biblioteca TopShelf .

Cree una aplicación de consola y luego configure la configuración en su 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 su servicio, simplemente presione F5 en Visual Studio.

Para instalar el servicio, escriba cmd "console.exe install"

Luego puede iniciar y detener el servicio en el administrador de servicios de Windows.

Misterhex
fuente
Su licencia era demasiado confusa para entender
l --''''''--------- '' '' '' '' '' ''
Utilizan la licencia de Apache afaik. Topshelf es la forma más fácil que he usado para desarrollar y depurar servicios de Windows. Súper fácil de usar. Desarrollar como una aplicación de consola. Instalar como servicio con un interruptor de línea de comando. Muy recomendable.
roba el
TopShelf me ahorró toneladas de tiempo. Thx
L_7337
8

Creo que depende del sistema operativo que esté utilizando, Vista es mucho más difícil de conectar a los Servicios, debido a la separación entre sesiones.

Las dos opciones que he usado en el pasado son:

  • Use GFlags (en las Herramientas de depuración para Windows) para configurar un depurador permanente para un proceso. Esto existe en la clave de registro "Opciones de ejecución de archivos de imagen" y es increíblemente útil. Creo que deberá ajustar la configuración del Servicio para habilitar "Interactuar con el escritorio". Lo uso para todo tipo de depuración, no solo para servicios.
  • La otra opción es separar un poco el código, de modo que la parte del servicio sea intercambiable con un inicio normal de la aplicación. De esa manera, puede usar un indicador de línea de comando simple y ejecutarlo como un proceso (en lugar de un Servicio), lo que facilita mucho la depuración.

Espero que esto ayude.

RichS
fuente
+1 para GFlags. Esto es especialmente útil si no puede modificar el código fuente (o si no lo tiene).
Chris Gillum
6

Me gusta poder depurar todos los aspectos de mi servicio, incluida cualquier inicialización en OnStart (), mientras lo ejecuto con un comportamiento de servicio completo en el marco del SCM ... sin modo "consola" o "aplicación".

Hago esto creando un segundo servicio, en el mismo proyecto, para usar para la depuración. El servicio de depuración, cuando se inicia como de costumbre (es decir, en el complemento MMC de servicios), crea el proceso de host del servicio. Esto le proporciona un proceso para adjuntar el depurador a pesar de que aún no ha comenzado su servicio real. Después de adjuntar el depurador al proceso, inicie su servicio real y podrá acceder a él en cualquier parte del ciclo de vida del servicio, incluido OnStart ().

Debido a que requiere una intrusión de código muy mínima, el servicio de depuración se puede incluir fácilmente en su proyecto de configuración del servicio, y se elimina fácilmente de su versión de producción comentando una sola línea de código y eliminando un solo instalador del proyecto.

Detalles:

1) Suponiendo que está implementando MyService, también cree MyServiceDebug. Agregue ambos a la ServiceBasematriz de la siguiente Program.csmanera:

    /// <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) Agregue el servicio real Y el servicio de depuración al instalador del proyecto para el proyecto de servicio:

ingrese la descripción de la imagen aquí

Ambos servicios (real y depuración) se incluyen cuando agrega la salida del proyecto de servicio al proyecto de configuración para el servicio. Después de la instalación, ambos servicios aparecerán en el complemento service.msc MMC.

3) Inicie el servicio de depuración en MMC.

4) En Visual Studio, adjunte el depurador al proceso iniciado por el servicio de depuración.

5) Inicie el servicio real y disfrute de la depuración.

BitMask777
fuente
5

Cuando escribo un servicio pongo toda la lógica del servicio en un proyecto dll y creo dos "hosts" que llaman a este dll, uno es un servicio de Windows y el otro es una aplicación de línea de comandos.

Utilizo la aplicación de línea de comandos para depurar y adjunto el depurador al servicio real solo para errores que no puedo reproducir en la aplicación de línea de comandos.

Si utiliza este enfoque, recuerde que debe probar todo el código mientras se ejecuta en un servicio real, mientras que la herramienta de línea de comandos es una buena ayuda para la depuración, es un entorno diferente y no se comporta exactamente como un servicio real.

Nir
fuente
4

Al desarrollar y depurar un servicio de Windows, normalmente lo ejecuto como una aplicación de consola agregando un parámetro de inicio / console y verificando esto. Hace la vida mucho más fácil.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}
Maurice
fuente
Hasta que tenga que depurar problemas específicos del servicio.
leppie
Es cierto que debe adjuntar el depurador al proceso de servicio real. Pero en la mayoría de los casos, los errores aparecerán de cualquier manera y el desarrollo es mucho más fácil.
Maurice
4

¿Qué hay de Debugger.Break () en la primera línea?

leppie
fuente
2

Para depurar los servicios de Windows combino GFlags y un archivo .reg creado por regedit.

  1. Ejecute GFlags, especificando el nombre del exe y vsjitdebugger
  2. Ejecute regedit y vaya a la ubicación donde GFlags establece sus opciones
  3. Elija "Exportar clave" en el menú archivo
  4. Guarde ese archivo en algún lugar con la extensión .reg
  5. Cada vez que desee depurar el servicio: haga doble clic en el archivo .reg
  6. Si desea detener la depuración, haga doble clic en el segundo archivo .reg

O guarde los siguientes fragmentos y reemplace servicename.exe con el nombre ejecutable deseado.


debugon.reg:

Editor del Registro de Windows Versión 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \ servicename.exe]
"GlobalFlag" = "0x00000000"
"Debugger" = "vsjitdebugger.exe"

debugoff.reg:

Editor del Registro de Windows Versión 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \ servicename.exe]
"GlobalFlag" = "0x00000000"

fuente
¿Esto todavía funciona en Win 7 / Win 2008? Es el enfoque de support.microsoft.com/kb/824344 pero depende de servicios interactivos, y pensé que los mataron. Siempre solía ser mi opción preferida (ya que los problemas de inicio podrían surgir en la producción, donde insertar un Debugger.Break () en el código podría no ser una opción).
muelles7
1

Para la programación rutinaria de cosas pequeñas, he hecho un truco muy simple para depurar fácilmente mi servicio:

Al inicio del servicio, verifico si hay un parámetro de línea de comando "/ debug". Si se llama al servicio con este parámetro, no hago el inicio del servicio habitual, sino que inicio a todos los oyentes y solo visualizo un cuadro de mensaje "Depuración en progreso, presiono ok para finalizar".

Entonces, si mi servicio se inicia de la manera habitual, comenzará como servicio, si se inicia con el parámetro / depuración de la línea de comando, actuará como un programa normal.

En VS simplemente agregaré / depuraré como parámetro de depuración e iniciaré el programa de servicio directamente.

De esta manera, puedo depurar fácilmente la mayoría de los problemas pequeños. Por supuesto, algunas cosas aún deberán ser depuradas como servicio, pero para el 99% esto es lo suficientemente bueno.

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

Yo uso una variación en la respuesta de JOP. Con los parámetros de la línea de comandos, puede establecer el modo de depuración en el IDE con las propiedades del proyecto o mediante el administrador de servicios de Windows.

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

Simplemente ponga su almuerzo de depuración en cualquier lugar y adjunte Visualstudio al inicio

#if DEBUG
    Debugger.Launch();
#endif

También debe iniciar VS como Administatrator y debe permitir que un usuario diferente pueda depurar un proceso (como se explica aquí ):

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

Use el proyecto de plantilla de servicio de Windows C # para crear una nueva aplicación de servicio https://github.com/HarpyWar/windows-service-template

Hay modo de consola / servicio detectado automáticamente, instalador automático / desinstalador de su servicio y se incluyen varias de las funciones más utilizadas.

HarpyWar
fuente
1

Aquí está el método simple que utilicé para probar el servicio, sin ningún método adicional de "depuración" y con pruebas de unidad VS integradas.

[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
fuente
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
fuente
Esto es más fácil. simplemente cambie la configuración de la solución a depurar, ejecute el proyecto / solución, agregue puntos de interrupción a medida que avanza.
Bahamut
0

Tienes dos opciones para hacer la depuración.

  1. crear un archivo de registro: Personalmente, prefiero un archivo de registro separado como un archivo de texto en lugar de usar el registro de la aplicación o el registro de eventos, pero esto le costará mucho en nombre del tiempo, porque aún es difícil determinar dónde está la ubicación exacta del error
  2. Convierta la aplicación a la aplicación de consola: esto le permitirá tener todas las herramientas de depuración que podemos usar en VS.

Consulte ESTA publicación de blog que creé para el tema.

Sandaru
fuente
0

Solo pegar

Debugger.Break();

en cualquier parte de tu código.

Por ejemplo ,

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);
        }
    }

Golpeará Debugger.Break();cuando ejecutes tu programa.

Chutipong Roobklom
fuente
0

La mejor opción es usar el espacio de nombres ' System.Diagnostics '.

Incluya su código en el bloque if if para el modo de depuración y el modo de liberación como se muestra a continuación para cambiar entre el modo de depuración y liberación en 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
fuente