Wie kann ein .NET Windows-Dienst direkt nach der Installation gestartet werden?

88

Neben dem service.StartType = ServiceStartMode.Automatic startet mein Service nach der Installation nicht

Lösung

Fügte diesen Code in meinen ProjectInstaller ein

protected override void OnAfterInstall(System.Collections.IDictionary savedState)
{
    base.OnAfterInstall(savedState);
    using (var serviceController = new ServiceController(this.serviceInstaller1.ServiceName, Environment.MachineName))
        serviceController.Start();
}

Vielen Dank an ScottTx und Francis B.

Jader Dias
quelle
Es startet nicht direkt nach der Installation oder nicht beim Neustart?
Chris Van Opstal

Antworten:

21

Sie können dies alles in Ihrer ausführbaren Dienstdatei als Reaktion auf Ereignisse tun, die vom InstallUtil-Prozess ausgelöst wurden. Überschreiben Sie das OnAfterInstall-Ereignis, um eine ServiceController-Klasse zum Starten des Dienstes zu verwenden.

http://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceinstaller.aspx

ScottTx
quelle
3
Dies ist eine gute Lösung, erfordert jedoch weiterhin die Verwendung des InstallUtil-Dienstprogramms. Wenn Sie InstallUtil bereits als Teil Ihrer Installation bereitstellen, ist dies am sinnvollsten. Wenn Sie jedoch auf das Verpacken von InstallUtil verzichten möchten, verwenden Sie die Befehlszeilenlösung.
Matt Davis
181

Ich habe für das Erstellen eines Windows - Dienstes in C # ein Schritt- für -Schritt - Verfahren geschrieben hier . Es hört sich so an, als wären Sie zumindest bis zu diesem Punkt und jetzt fragen Sie sich, wie Sie den Dienst starten sollen, sobald er installiert ist. Wenn Sie die StartType-Eigenschaft auf Automatisch setzen, wird der Dienst nach dem Neustart Ihres Systems automatisch gestartet, aber nach der Installation wird der Dienst nicht (wie Sie festgestellt haben) automatisch gestartet.

Ich erinnere mich nicht, wo ich es ursprünglich gefunden habe (vielleicht Marc Gravell?), Aber ich habe online eine Lösung gefunden, mit der Sie Ihren Dienst installieren und starten können, indem Sie Ihren Dienst selbst ausführen. Hier ist die Schritt-für-Schritt-Anleitung:

  1. Strukturieren Sie die Main()Funktion Ihres Dienstes wie folgt:

    static void Main(string[] args)
    {
        if (args.Length == 0) {
            // Run your service normally.
            ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
            ServiceBase.Run(ServicesToRun);
        } else if (args.Length == 1) {
            switch (args[0]) {
                case "-install":
                    InstallService();
                    StartService();
                    break;
                case "-uninstall":
                    StopService();
                    UninstallService();
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }
  2. Hier ist der unterstützende Code:

    using System.Collections;
    using System.Configuration.Install;
    using System.ServiceProcess;
    
    private static bool IsInstalled()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                ServiceControllerStatus status = controller.Status;
            } catch {
                return false;
            }
            return true;
        }
    }
    
    private static bool IsRunning()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            if (!IsInstalled()) return false;
            return (controller.Status == ServiceControllerStatus.Running);
        }
    }
    
    private static AssemblyInstaller GetInstaller()
    {
        AssemblyInstaller installer = new AssemblyInstaller(
            typeof(YourServiceType).Assembly, null);
        installer.UseNewContext = true;
        return installer;
    }
  3. Weiter mit dem unterstützenden Code ...

    private static void InstallService()
    {
        if (IsInstalled()) return;
    
        try {
            using (AssemblyInstaller installer = GetInstaller()) {
                IDictionary state = new Hashtable();
                try {
                    installer.Install(state);
                    installer.Commit(state);
                } catch {
                    try {
                        installer.Rollback(state);
                    } catch { }
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void UninstallService()
    {
        if ( !IsInstalled() ) return;
        try {
            using ( AssemblyInstaller installer = GetInstaller() ) {
                IDictionary state = new Hashtable();
                try {
                    installer.Uninstall( state );
                } catch {
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void StartService()
    {
        if ( !IsInstalled() ) return;
    
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Running ) {
                    controller.Start();
                    controller.WaitForStatus( ServiceControllerStatus.Running, 
                        TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
    
    private static void StopService()
    {
        if ( !IsInstalled() ) return;
        using ( ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Stopped ) {
                    controller.Stop();
                    controller.WaitForStatus( ServiceControllerStatus.Stopped, 
                         TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
  4. Führen Sie zu diesem Zeitpunkt nach der Installation Ihres Dienstes auf dem Zielcomputer Ihren Dienst einfach über die Befehlszeile (wie bei jeder normalen Anwendung) mit dem -installBefehlszeilenargument aus, um Ihren Dienst zu installieren und zu starten.

Ich denke, ich habe alles behandelt, aber wenn Sie feststellen, dass dies nicht funktioniert, lassen Sie es mich bitte wissen, damit ich die Antwort aktualisieren kann.

Matt Davis
quelle
12
Beachten Sie, dass für diese Lösung InstallUtil.exe nicht erforderlich ist, sodass Sie sie nicht als Teil Ihres Installationsprogramms bereitstellen müssen.
Matt Davis
2
Was bringt es mit den leeren "catch {throw;}" - Klauseln? Außerdem ist es wahrscheinlich keine gute Idee, Fehler durch "Rollback ()" auszublenden, da diese Situation das System im Grunde genommen in einem undefinierten Zustand belässt (Sie haben versucht, einen Dienst zu installieren, sind irgendwo in der Mitte fehlgeschlagen und konnten ihn nicht rückgängig machen ). Sie sollten dem Benutzer zumindest "zeigen", dass etwas faul ist - oder schreibt die Funktion Rollback () einige Nachrichten an die Konsole?
Christian.K
5
Das Rollback schreibt Daten in die Konsole. Was die leeren Fangblöcke betrifft, ist es eine Debugging-Sache. Ich kann einen Haltepunkt in die throw-Anweisung setzen, um eventuelle Ausnahmen zu untersuchen.
Matt Davis
4
Ich erhalte eine Fehlermeldung: Der Typ- oder Namespace-Name 'YourServiceType' wurde nicht gefunden (fehlt Ihnen eine using-Direktive oder eine Assembly-Referenz?
Yogesh
5
YourServiceTypeist das, was ProjectInstallerSie dem Dienst hinzugefügt haben, der ServiceInstallerandServiceProcessInstaller
bansi
6

Visual Studio

Wenn Sie ein Setup-Projekt mit VS erstellen, können Sie eine benutzerdefinierte Aktion erstellen, die eine .NET-Methode zum Starten des Dienstes aufruft. Es wird jedoch nicht wirklich empfohlen, verwaltete benutzerdefinierte Aktionen in einer MSI zu verwenden. Siehe diese Seite .

ServiceController controller  = new ServiceController();
controller.MachineName = "";//The machine where the service is installed;
controller.ServiceName = "";//The name of your service installed in Windows Services;
controller.Start();

InstallShield oder Wise

Wenn Sie InstallShield oder Wise verwenden, bieten diese Anwendungen die Möglichkeit, den Dienst zu starten. Bei Wise müssen Sie beispielsweise eine Dienststeuerungsaktion hinzufügen. In dieser Aktion geben Sie an, ob Sie den Dienst starten oder stoppen möchten.

Wix

Mit Wix müssen Sie den folgenden XML-Code unter der Komponente Ihres Dienstes hinzufügen. Weitere Informationen hierzu finden Sie auf dieser Seite .

<ServiceInstall 
    Id="ServiceInstaller"  
    Type="ownProcess"  
    Vital="yes"  
    Name=""  
    DisplayName=""  
    Description=""  
    Start="auto"  
    Account="LocalSystem"   
    ErrorControl="ignore"   
    Interactive="no">  
        <ServiceDependency Id="????"/> ///Add any dependancy to your service  
</ServiceInstall>
Francis B.
quelle
5

Sie müssen am Ende der Sequenz 'ExecuteImmediate' in der MSI eine benutzerdefinierte Aktion hinzufügen, wobei Sie den Komponentennamen der EXE-Datei oder einen Stapel (sc start) als Quelle verwenden. Ich glaube nicht, dass dies mit Visual Studio möglich ist. Möglicherweise müssen Sie dafür ein echtes MSI-Authoring-Tool verwenden.

Otávio Décio
quelle
4

Um es direkt nach der Installation zu starten, generiere ich eine Batch-Datei mit installutil, gefolgt von sc start

Es ist nicht ideal, aber es funktioniert ...

Matt
quelle
4

Verwenden Sie die .NET ServiceController-Klasse, um es zu starten, oder geben Sie den Befehlszeilenbefehl ein, um es zu starten --- "net start servicename". So oder so funktioniert.

ScottTx
quelle
4

Um die Antwort von ScottTx zu ergänzen, finden Sie hier den eigentlichen Code zum Starten des Dienstes, wenn Sie dies auf Microsoft-Weise tun (z. B. mithilfe eines Setup-Projekts usw.).

(Entschuldigen Sie den VB.net-Code, aber das ist es, woran ich festhalte)

Private Sub ServiceInstaller1_AfterInstall(ByVal sender As System.Object, ByVal e As System.Configuration.Install.InstallEventArgs) Handles ServiceInstaller1.AfterInstall
    Dim sc As New ServiceController()
    sc.ServiceName = ServiceInstaller1.ServiceName

    If sc.Status = ServiceControllerStatus.Stopped Then
        Try
            ' Start the service, and wait until its status is "Running".
            sc.Start()
            sc.WaitForStatus(ServiceControllerStatus.Running)

            ' TODO: log status of service here: sc.Status
        Catch ex As Exception
            ' TODO: log an error here: "Could not start service: ex.Message"
            Throw
        End Try
    End If
End Sub

Um den obigen Ereignishandler zu erstellen, rufen Sie den ProjectInstaller-Designer auf, in dem sich die beiden Steuerelemente befinden. Klicken Sie auf das Steuerelement ServiceInstaller1. Gehen Sie zum Eigenschaftenfenster unter Ereignisse und dort finden Sie das AfterInstall-Ereignis.

Hinweis: Fügen Sie den obigen Code nicht unter das AfterInstall-Ereignis für ServiceProcessInstaller1 ein. Aus Erfahrung wird es nicht funktionieren. :) :)

goku_da_master
quelle
VB.net Code ist nicht schlecht! Für diejenigen von uns, die in mehreren Sprachen arbeiten, ist es schön, den Code nicht von C konvertieren zu müssen!
Steve Reed Sr
Vielen Dank, dies hat mir geholfen herauszufinden, wie ein Dienst automatisch gestartet wird.
Charles Owen
0

Die einfachste Lösung finden Sie hier install-windows-service-without-installutil-exe von @ Hoàng Long

@echo OFF
echo Stopping old service version...
net stop "[YOUR SERVICE NAME]"
echo Uninstalling old service version...
sc delete "[YOUR SERVICE NAME]"

echo Installing service...
rem DO NOT remove the space after "binpath="!
sc create "[YOUR SERVICE NAME]" binpath= "[PATH_TO_YOUR_SERVICE_EXE]" start= auto
echo Starting server complete
pause
Robert Green MBA
quelle