Come eseguo il debug dei servizi Windows in Visual Studio?


85

È possibile eseguire il debug dei servizi Windows in Visual Studio?

Ho usato il codice come

System.Diagnostics.Debugger.Break();

ma sta dando qualche errore di codice come:

Ho ricevuto due errori di evento: eventID 4096 VsJITDebugger e "Il servizio non ha risposto alla richiesta di avvio o controllo in modo tempestivo".

Risposte:


124

Usa il codice seguente nel OnStartmetodo di servizio :

System.Diagnostics.Debugger.Launch();

Scegli l'opzione Visual Studio dal messaggio popup.

Nota: per utilizzarlo solo in modalità Debug, è #if DEBUGpossibile utilizzare una direttiva del compilatore, come segue. Ciò impedirà il debug accidentale o in modalità di rilascio su un server di produzione.

#if DEBUG
    System.Diagnostics.Debugger.Launch();
#endif

9
Ricorda di eseguire VS come amministratore. Quindi sarà disponibile nell'elenco.
Michael

1
Qualcuno può chiarire cosa si intende per messaggio pop-up? Quando / come appare?
Mike

@ Mike, installa e avvia il servizio, apparirà.
Harshit

@ Mike, è una finestra di dialogo di Windows che si apre sul desktop interattivo (connesso) e chiede se si desidera scegliere un'app con cui eseguire il debug del processo. Se scegli VS, avvierà il debugger e si collegherà al processo
Chris Johnson

63

Puoi anche provare questo.

  1. Crea il tuo servizio Windows, installa e avvia…. Cioè, i servizi di Windows devono essere in esecuzione nel tuo sistema.
  2. Mentre il tuo servizio è in esecuzione, vai al menu Debug , fai clic su Collega processo (o processo nel vecchio Visual Studio)
  3. Trova il tuo servizio in esecuzione, quindi assicurati che Mostra processo da tutti gli utenti e Mostra processi in tutte le sessioni sia selezionato, in caso contrario selezionalo.

inserisci qui la descrizione dell'immagine

  1. Fare clic sul pulsante Allega
  2. Fare clic su OK
  3. Fare clic su Chiudi
  4. Imposta un punto di interruzione nella posizione desiderata e attendi l'esecuzione. Eseguirà il debug automatico ogni volta che il codice raggiunge quel punto.
  5. Ricorda, metti il ​​tuo punto di interruzione in un punto raggiungibile , se è onStart (), quindi interrompi e riavvia il servizio

(Dopo molte ricerche su Google, ho trovato questo in "Come eseguire il debug dei servizi di Windows in Visual Studio".)


2
Non riesco a vedere questa opzione nell'aggiornamento 5. VS2013 :(
sandeep talabathula

1
Ma devi eseguire il tuo Vs-2017 come amministratore
chozha rajan

1
Ho provato questo. Ha funzionato con un punto di interruzione in onStop ma non in onStart perché quando il servizio si interrompe il debugger viene
scollegato

22

È necessario separare tutto il codice che farà le cose dal progetto di servizio in un progetto separato, quindi creare un'applicazione di test che è possibile eseguire ed eseguire il debug normalmente.

Il progetto di servizio sarebbe solo la shell necessaria per implementare la parte di servizio di esso.


OOW !! ctrl + C poi ctrl + V, intendo nuovo progetto. Sì, quello che sto facendo solo io. Non è possibile allegare alcun processo al debug o qualsiasi altra opzione piuttosto che un progetto separato.?
PawanS

1
Ovviamente è possibile, ma è molto più facile sviluppare un servizio Windows se rimuovi la parte del servizio durante lo sviluppo.
Lasse V. Karlsen

hmmm ... questo è un buon modo ma semplicemente raddoppia il lavoro. Ho pensato che sarebbe esistito un altro modo.
PawanS

9
Non vedo come potrebbe "raddoppiare" il lavoro. Certo, aggiungerà un piccolo sovraccarico per creare il progetto extra e separare il codice nel servizio in un terzo progetto, ma a parte questo, non faresti una copia del codice, lo sposteresti, e fare riferimento a quel progetto.
Lasse V. Karlsen

3
^ + 1. Raddoppia il lavoro di gestione del servizio, che è praticamente zero in termini di tempo di sviluppo, e lo fai solo una volta. Il debug di un servizio è DOLOROSO, piuttosto fallo doppio avvio come riga di comando. Controlla su Google le classi wrapper predefinite che consentono di farlo (usano la riflessione per simulare l'avvio / arresto nessuna classe di servizio). un'ora di lavoro, tonnellate di risparmi, perdita netta: negativa - guadagni tempo.
TomTom

14

O quello come suggerito da Lasse V. Karlsen, o imposta un ciclo nel tuo servizio che aspetterà il collegamento di un debugger. Il più semplice è

while (!Debugger.IsAttached)
{
    Thread.Sleep(1000);
}

... continue with code

In questo modo puoi avviare il servizio e all'interno di Visual Studio scegli "Allega al processo ..." e collegalo al tuo servizio che poi riprenderà la normale esecuzione.


dove dovrei mettere il codice sopra ... e nel processo di collegamento ottengo il mio servizio denominato disable
PawanS

3
abbiamo anche usato un codice come questo if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Kirill Kovalenko

quel codice dovrebbe essere il più presto possibile prima che sia possibile eseguire qualsiasi codice di cui si desidera eseguire il debug.
Pauli Østerø

@Pawan: In Start/ OnStart()Immagino
abatishchev

@ Kirill: usa le tilde per evidenziare il codice all'interno dei commenti, ad esempiofoo(bar)
abatishchev

7

Dato che ServiceBase.OnStartha protectedvisibilità, ho seguito il percorso di riflessione per ottenere il debug.

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

Nota che Threadè, per impostazione predefinita, un thread in primo piano. returnL'ing da Mainmentre i thread del servizio falso sono in esecuzione non terminerà il processo.


Poiché OnStart dovrebbe tornare rapidamente, non dovresti aver bisogno di farlo in un altro thread. Tuttavia, se il servizio non avvia un altro thread, il processo verrà chiuso immediatamente.
Matt Connolly

@ MattConnolly Su quest'ultimo: se necessario, cambio il codice sopra per avviare un thread in primo piano che dorme per sempre (prima della normale elaborazione).
ta.speot.is

Questa dovrebbe essere una vera risposta. Funziona magnificamente!
lentyai

4

Un articolo di Microsoft spiega come eseguire il debug di un servizio Windows qui e quale parte può perdere chiunque se ne esegue il debug collegandosi a un processo.

Di seguito è riportato il mio codice di lavoro. Ho seguito l'approccio suggerito da Microsoft.

Aggiungi questo codice 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);
    }
}

Aggiungi questo codice alla classe ServiceMonitor.

internal void TestOnStartAndOnStop(string[] args)
{
    this.OnStart(args);
    Console.ReadLine();
    this.OnStop();
}

Ora vai su Proprietà progetto , seleziona la scheda "Applicazione" e seleziona Tipo di output come "Applicazione console" durante il debug o "Applicazione Windows" quando hai finito con il debug, ricompila e installa il tuo servizio.

Inserisci qui la descrizione dell'immagine


c'è un modo per impostare l'output su Console Application in Debug e Window Application in versione?
kofifus

3

Puoi creare un'applicazione console. Uso questa mainfunzione:

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

La mia ImportFileServiceclasse è esattamente la stessa dell'applicazione del mio servizio Windows, ad eccezione di inheritant ( ServiceBase).


è sullo stesso progetto o su un altro progetto per questa app console
PawanS

Sono 2 progetti diversi con classi simili. Nel mio caso, è un servizio semplice con solo la classe ImportFileService che è duplicata. Quando voglio sviluppare / testare, uso consoleapp e quindi copia / incolla. Come ha detto Lasse V. Karlsen, è un programma di debug, tutta la logica (business) è su un terzo progetto.
kerrubin

OnStart non è protetto?
Joe Phillips

Sì, lo è. È per questo che ho detto "tranne il inheritant ( ServiceBase).". Trovo più facile eseguire il debug in un'app console, ma capisco se questo non convince tutti.
kerrubin

3

Uso un ottimo pacchetto Nuget chiamato ServiceProcess.Helpers.

E cito ...

Aiuta il debug dei servizi Windows creando un'interfaccia utente di riproduzione / interruzione / pausa durante l'esecuzione con un debugger collegato, ma consente anche di installare ed eseguire il servizio dall'ambiente Windows Server.

Tutto questo con una riga di codice.

http://windowsservicehelper.codeplex.com/

Una volta installato e cablato, tutto ciò che devi fare è impostare il tuo progetto di servizio Windows come progetto di avvio e fare clic su Avvia sul tuo debugger.


Grazie per la condivisione! È stata di gran lunga la soluzione più semplice!
Wellington Zanelli

2

Puoi anche provare il metodo System.Diagnostics.Debugger.Launch () . Aiuta a portare il puntatore del debugger nella posizione specificata e puoi quindi eseguire il debug del codice.

Prima di questo passaggio , installa il tuo service.exe utilizzando la riga di comando del prompt dei comandi di Visual Studio - installutil projectservice.exe

Quindi avvia il servizio dal Pannello di controllo -> Strumenti di amministrazione -> Gestione computer -> Servizio e applicazione -> Servizi -> Nome del servizio


2

Ho appena aggiunto questo codice alla mia classe di servizio in modo da poter chiamare indirettamente OnStart, simile per OnStop.

    public void MyOnStart(string[] args)
    {
        OnStart(args);
    }

2

Sto utilizzando il /Consoleparametro nel progetto Visual Studio DebugOpzioni di avvioArgomenti della riga di 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() {....}
}

2

Ho trovato questa domanda, ma credo che manchi una risposta chiara e semplice.

Non voglio collegare il mio debugger a un processo, ma voglio comunque poter chiamare il servizio OnStarte i OnStopmetodi. Voglio anche che venga eseguito come applicazione console in modo da poter registrare le informazioni da NLog a una console.

Ho trovato queste guide brillanti che fanno questo:

Inizia modificando i progetti Output typein Console Application.

Inserisci qui la descrizione dell'immagine

Cambia il tuo Program.csin questo modo:

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

Quindi aggiungere il seguente metodo per consentire l'esecuzione dei servizi in modalità interattiva.

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

Ottimo codice! Semplice, efficace. +1. Ma altrettanto facile ho reso questa un'app Forms. Odio davvero le app per console. Inoltre, puoi facilmente implementare un pulsante Form per ogni evento di servizio.
Roland

1

Sfortunatamente, se stai tentando di eseguire il debug di qualcosa all'inizio di un'operazione del servizio Windows, il "collegamento" al processo in esecuzione non funzionerà. Ho provato a utilizzare Debugger.Break () all'interno della procedura OnStart, ma con un'applicazione compilata Visual Studio 2010 a 64 bit, il comando break genera un errore come questo:

System error 1067 has occurred.

A quel punto, è necessario impostare un'opzione "Esecuzione file immagine" nel registro per il proprio eseguibile. Ci vogliono cinque minuti per la configurazione e funziona molto bene. Ecco un articolo di Microsoft in cui sono presenti i dettagli:

Procedura: avviare automaticamente il debugger


1

Prova la riga di comando degli eventi post-compilazione di Visual Studio .

Prova ad aggiungere questo in post-build:

@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 l'errore di compilazione con un messaggio come Error 1 The command "@echo off sc query "ServiceName" > nulcosì via, Ctrl+ Cpoi Ctrl+ Vil messaggio di errore nel Blocco note e guarda l'ultima frase del messaggio.

Potrebbe dire exited with code x. Cerca il codice in qualche errore comune qui e vedi come risolverlo.

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.

Maggiori informazioni sui codici di errore qui .

E se l'errore di compilazione con un messaggio come questo,

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

apri cmd, quindi prova a ucciderlo prima con taskkill /fi "services eq ServiceName" /f

Se tutto va bene, F5dovrebbe essere sufficiente per eseguire il debug.


0

Nel OnStartmetodo, eseguire le operazioni seguenti.

protected override void OnStart(string[] args)
{
    try
    {
        RequestAdditionalTime(600000);
        System.Diagnostics.Debugger.Launch(); // Put breakpoint here.

        .... Your code
    }
    catch (Exception ex)
    {
        .... Your exception code
    }
}

Quindi esegui un prompt dei comandi come amministratore e inserisci quanto segue:

c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand

La riga sopra creerà test-xyzService nell'elenco dei servizi.

Per avviare il servizio, questo ti chiederà di collegarti al debutto in Visual Studio o meno.

c:\> sc start text-xyzService

Per interrompere il servizio:

c:\> sc stop test-xyzService

Per eliminare o disinstallare:

c:\> sc delete text-xyzService

0

Eseguire il debug di un servizio Windows su http (testato con VS 2015 Update 3 e .Net FW 4.6)

Innanzitutto, devi creare un progetto console all'interno della tua soluzione VS (Aggiungi -> Nuovo progetto -> Applicazione console).

All'interno del nuovo progetto, crea una classe "ConsoleHost" con quel codice:

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 questo è il codice per 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();
    }
}

Le configurazioni come le stringhe di connessione devono essere copiate nel file App.config del progetto Console.

Per avviare la console, fare clic con il tasto destro del mouse su Progetto console e fare clic su Debug -> Avvia nuova istanza.


0

Aggiungi semplicemente un costruttore alla tua classe di servizio (se non lo hai già). Di seguito, puoi controllare ed esempio per Visual Basic .net.

Public Sub New()
   OnStart(Nothing) 
End Sub

Successivamente, fai clic con il pulsante destro del mouse sul progetto e seleziona " Debug -> Avvia una nuova istanza ".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.