web-dev-qa-db-ger.com

Wie debugge ich Windows-Dienste in Visual Studio?

Ist es möglich, die Windows-Dienste in Visual Studio zu debuggen?

Ich habe Code wie verwendet

System.Diagnostics.Debugger.Break();

aber es gibt einige Codefehler wie:

Ich habe zwei Ereignisfehler erhalten: Ereignis-ID 4096 VsJITDebugger und "Der Dienst hat Nicht rechtzeitig auf die Start- oder Steuerungsanforderung "

72
PawanS

Sie können dies auch versuchen.

  1. Erstellen Sie Ihren Windows-Dienst und installieren und starten Sie…. Das heißt, Windows-Dienste müssen in Ihrem System ausgeführt werden.
  2. Wechseln Sie während der Ausführung Ihres Dienstes zum Menü Debug und klicken Sie auf Attach Process (oder Prozess in altem Visual Studio).
  3. Suchen Sie nach dem laufenden Dienst, und stellen Sie sicher, dass Show von allen Benutzern und Prozesse in allen Sitzungen anzeigen ausgewählt ist. Andernfalls wählen Sie ihn aus. 

enter image description here

  1. Klicken Sie auf die Schaltfläche Attach 
  2. Klicken Sie auf OK
  3. Klicken Sie auf Schließen
  4. Setzen Sie einen Haltepunkt an Ihrem gewünschten Ort und warten Sie auf Ausführen. Es wird automatisch ein Debugging durchgeführt, wenn Ihr Code diesen Punkt erreicht.
  5. Denken Sie daran, setzen Sie Ihren Haltepunkt an erreichbarer Ort. Wenn es onStart () ist, stoppen Sie den Dienst und starten Sie ihn erneut

(Nach langem Googeln habe ich dies in "So debuggen Sie die Windows-Dienste in Visual Studio" gefunden.)

58
PawanS

Verwenden Sie den folgenden Code in der Dienstvariante OnStart:

System.Diagnostics.Debugger.Launch();

Wählen Sie die Visual Studio-Option aus der Popup-Nachricht.

Hinweis: Für die Verwendung nur im Debug-Modus kann eine #if DEBUG-Compiler-Direktive wie folgt verwendet werden. Dies verhindert ein versehentliches oder debuggen im Freigabemodus auf einem Produktionsserver.

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

Sie sollten den gesamten Code, den do stuff aus dem Serviceprojekt ausführen soll, in ein separates Projekt aufteilen und dann eine Testanwendung erstellen, die Sie normalerweise ausführen und debuggen können.

Das Serviceprojekt wäre nur die Shell, die zur Implementierung des Serviceteils erforderlich ist.

Entweder das, wie von Lasse V. Karlsen vorgeschlagen, oder eine Schleife in Ihrem Dienst einrichten, die darauf wartet, dass ein Debugger angeschlossen wird. Das einfachste ist

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

... continue with code

Auf diese Weise können Sie den Dienst starten, und in Visual Studio wählen Sie "An Prozess anhängen ..." und an Ihren Dienst anhängen, der dann wieder normal ausgeführt wird.

14
Pauli Østerø

Da ServiceBase.OnStartprotected Sichtbarkeit hat, bin ich den Reflection-Weg gegangen, um das Debugging zu erreichen.

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

Beachten Sie, dass Thread standardmäßig ein Vordergrundthread ist. returning von Main während die Faux-Service-Threads ausgeführt werden, beendet den Prozess nicht.

6
ta.speot.is

Sie können eine Konsolenanwendung erstellen. Ich verwende diese main-Funktion:

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

Meine ImportFileService-Klasse stimmt genau mit der in der Anwendung meines Windows-Dienstes überein, mit Ausnahme des Erben (ServiceBase).

3
kerrubin

In einem Microsoft-Artikel wird erläutert, wie Sie einen Windows-Dienst hier debuggen können und welchen Teil jeder übersehen kann, wenn er ihn durch Anhängen an einen Prozess debuggt.

Unten ist mein Arbeitscode. Ich habe den von Microsoft vorgeschlagenen Ansatz verfolgt.

Fügen Sie diesen Code zu program.cs hinzu:

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

Fügen Sie diesen Code der ServiceMonitor-Klasse hinzu.

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

Gehen Sie nun zu Projekteigenschaften, wählen Sie die Registerkarte "Anwendung" und wählen Sie Ausgabetyp als "Konsolenanwendung" beim Debuggen oder "Windows-Anwendung", wenn Sie mit dem Debuggen fertig sind, rekompilieren und installieren Sie Ihren Dienst.

Enter image description here

3

Sie können auch die Methode System.Diagnostics.Debugger.Launch () versuchen. Es hilft, den Debugger-Zeiger an den angegebenen Speicherort zu bringen, und Sie können dann den Code debuggen.

Vor diesem Schritt installieren Sie bitte Ihre service.exe mithilfe der Befehlszeile des Visual Studio-Befehls Prompt - installutil projectservice.exe  

Starten Sie dann Ihren Dienst über Systemsteuerung -> Verwaltung -> Computerverwaltung -> Dienst und Anwendung -> Dienste -> Name Ihres Dienstes

2

Ich habe diesen Code gerade zu meiner Serviceklasse hinzugefügt, damit ich indirekt OnStart aufrufen könnte, ähnlich für OnStop.

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

Ich verwende den /Console-Parameter im Visual Studio-Projekt Debug Startoptionen Befehlszeilenargumente :

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
Sean M

Wenn Sie gerade zu Beginn eines Windows-Dienstvorgangs versuchen, etwas zu debuggen, funktioniert das "Anhängen" an den laufenden Prozess nicht. Ich habe versucht, Debugger.Break () in der OnStart-Prozedur zu verwenden, aber bei einer 64-Bit-Anwendung, die mit Visual Studio 2010 kompiliert wurde, löst der Befehl break einen Fehler wie folgt aus:

System error 1067 has occurred.

Zu diesem Zeitpunkt müssen Sie in Ihrer Registry eine Option "Image File Execution" für Ihre ausführbare Datei einrichten. Das Einrichten dauert fünf Minuten und funktioniert sehr gut. Hier ist ein Microsoft-Artikel, in dem die Details aufgeführt sind:

Gewusst wie: Starten des Debuggers automatisch

1
Brian

Versuchen Sie es mit Visual Studios eigener Befehlszeile für Ereignisse nach der Erstellung .

Versuchen Sie dies nachträglich hinzuzufügen:

@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

Wenn der Erstellungsfehler mit einer Meldung wie Error 1 The command "@echo off sc query "ServiceName" > nul usw. auftritt, Ctrl + C dann Ctrl + V Geben Sie die Fehlermeldung in den Editor ein und lesen Sie den letzten Satz der Nachricht.

Es könnte exited with code x heißen. Suchen Sie hier nach dem Code in einem häufig auftretenden Fehler und erfahren Sie, wie Sie ihn beheben können.

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.

Mehr zu Fehlercodes hier .

Und wenn der Build-Fehler mit dieser Meldung,

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

öffne cmd und versuche es dann zuerst mit taskkill /fi "services eq ServiceName" /f zu töten

Wenn alles in Ordnung ist, F5 sollte ausreichen, um es zu debuggen.

1
asakura89

Führen Sie in der OnStart-Methode Folgendes aus.

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

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

Führen Sie dann eine Eingabeaufforderung als Administrator aus und geben Sie Folgendes ein:

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

In der obigen Zeile wird test-xyzService in der Serviceliste erstellt.

Um den Dienst zu starten, werden Sie aufgefordert, eine Verbindung zum Debüt in Visual Studio herzustellen oder nicht.

c:\> sc start text-xyzService

So beenden Sie den Dienst:

c:\> sc stop test-xyzService

Löschen oder deinstallieren:

c:\> sc delete text-xyzService
0
user3942119

Debuggen eines Windows-Dienstes über http (getestet mit VS 2015 Update 3 und .Net FW 4.6)

Zunächst müssen Sie ein Konsolenprojekt in Ihrer VS-Lösung erstellen (Hinzufügen -> Neues Projekt -> Konsolenanwendung).

Erstellen Sie im neuen Projekt eine Klasse "ConsoleHost" mit diesem 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();
    }
}

Und das ist der Code für die Klasse 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();
    }
}

Konfigurationen wie Verbindungszeichenfolgen sollten in die Datei App.config des Console-Projekts kopiert werden.

Klicken Sie mit der rechten Maustaste auf Console Project, und klicken Sie auf Debug -> Neue Instanz starten.

0
mggSoft

Ich habe diese Frage gefunden, aber ich denke, dass eine klare und einfache Antwort fehlt.

Ich möchte meinen Debugger nicht an einen Prozess anhängen, aber ich möchte trotzdem die Dienstmethoden OnStart und OnStop aufrufen können. Ich möchte auch, dass es als Konsolenanwendung ausgeführt wird, damit ich Informationen von NLog in eine Konsole protokollieren kann.

Ich habe diese genialen Führer gefunden, die folgendes tun:

Beginnen Sie, indem Sie die Projekte Output type in Console Application ändern.

 Enter image description here

Ändern Sie Ihren Program.cs folgendermaßen:

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

Fügen Sie dann die folgende Methode hinzu, um zuzulassen, dass Dienste im interaktiven Modus ausgeführt werden.

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

Ich benutze ein tolles Nuget-Paket namens ServiceProcess.Helpers.

Und ich zitiere...

Es hilft beim Debuggen von Windows-Diensten, indem es eine Play/Stop/Pause-Benutzeroberfläche erstellt, wenn ein Debugger ausgeführt wird. Außerdem kann der Dienst von der Windows Server-Umgebung installiert und ausgeführt werden.

All dies mit einer Codezeile.

http://windowsservicehelper.codeplex.com/

Nachdem Sie alles installiert und verkabelt haben, müssen Sie Ihr Windows-Dienstprojekt als Startprojekt festlegen und im Debugger auf Start klicken.

0