Come avviare un servizio Windows .NET subito dopo l'installazione?


88

Oltre a service.StartType = ServiceStartMode.Automatic il mio servizio non si avvia dopo l'installazione

Soluzione

Ho inserito questo codice nel mio ProjectInstaller

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

Grazie a ScottTx e Francis B.


Non si avvia subito dopo l'installazione o non si avvia al riavvio?
Chris Van Opstal

Risposte:


21

Puoi fare tutto questo dall'interno del tuo eseguibile del servizio in risposta agli eventi attivati ​​dal processo InstallUtil. Eseguire l'override dell'evento OnAfterInstall per utilizzare una classe ServiceController per avviare il servizio.

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


3
Questa è una buona soluzione, ma richiede comunque l'uso dell'utilità InstallUtil. Se stai già distribuendo InstallUtil come parte della tua installazione, questo ha più senso. Tuttavia, se si desidera rinunciare al packaging di InstallUtil, utilizzare la soluzione della riga di comando.
Matt Davis

182

Ho pubblicato una procedura dettagliata per la creazione di un servizio Windows in C # qui . Sembra che tu sia almeno a questo punto e ora ti stai chiedendo come avviare il servizio una volta installato. Impostando la proprietà StartType su Automatico, il servizio si avvierà automaticamente dopo il riavvio del sistema, ma (come hai scoperto) non avvierà automaticamente il servizio dopo l'installazione.

Non ricordo dove l'ho trovato originariamente (forse Marc Gravell?), Ma ho trovato una soluzione online che ti consente di installare e avviare il tuo servizio eseguendo effettivamente il tuo servizio stesso. Ecco il passo dopo passo:

  1. Struttura la Main()funzione del tuo servizio in questo modo:

    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. Ecco il codice di supporto:

    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. Continuando con il codice di supporto ...

    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. A questo punto, dopo aver installato il servizio sulla macchina di destinazione, è sufficiente eseguire il servizio dalla riga di comando (come qualsiasi normale applicazione) con l' -installargomento della riga di comando per installare e avviare il servizio.

Penso di aver coperto tutto, ma se trovi che questo non funziona, fammelo sapere in modo che io possa aggiornare la risposta.


13
Notare che questa soluzione non richiede l'uso di InstallUtil.exe, quindi non è necessario fornirla come parte del programma di installazione.
Matt Davis

3
Qual è il punto con le clausole vuote "catch {throw;}"? Inoltre, probabilmente nonèuna buona idea nascondere gli errori con "Rollback ()" poiché quella situazione fondamentalmente lascia il sistema in uno stato indefinito immagino (hai provato a installare un servizio, non è riuscito da qualche parte nel mezzo e non sei riuscito a annullarlo ). Dovresti almeno "mostrare" all'utente che c'è qualcosa di strano - o la funzione Rollback () scrive dei messaggi sulla console?
Christian.K

5
Il rollback scrive i dati sulla console. Per quanto riguarda i blocchi catch vuoti, è una cosa di debug. Posso inserire un punto di interruzione nell'istruzione throw per esaminare eventuali eccezioni che possono verificarsi.
Matt Davis,

4
Ricevo l'errore Errore: non è stato possibile trovare il tipo o il nome dello spazio dei nomi "YourServiceType" (ti manca una direttiva using o un riferimento all'assembly?
Yogesh

5
YourServiceTypeè quello che ProjectInstallerhai aggiunto al servizio che contiene ServiceInstallereServiceProcessInstaller
bansi

6

Visual Studio

Se stai creando un progetto di installazione con VS, puoi creare un'azione personalizzata che ha chiamato un metodo .NET per avviare il servizio. Tuttavia, non è davvero consigliabile utilizzare un'azione personalizzata gestita in un MSI. Vedi questa pagina .

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 o Wise

Se stai usando InstallShield o Wise, queste applicazioni forniscono l'opzione per avviare il servizio. Ad esempio con Wise, devi aggiungere un'azione di controllo del servizio. In questa azione, si specifica se si desidera avviare o arrestare il servizio.

Wix

Usando Wix devi aggiungere il seguente codice xml sotto il componente del tuo servizio. Per ulteriori informazioni a riguardo, puoi controllare questa pagina .

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

5

È necessario aggiungere un'azione personalizzata alla fine della sequenza "ExecuteImmediate" nell'MSI, utilizzando il nome del componente dell'EXE o un batch (sc start) come origine. Non penso che questo possa essere fatto con Visual Studio, potrebbe essere necessario utilizzare un vero strumento di creazione MSI per questo.


4

Per avviarlo subito dopo l'installazione, genero un file batch con installutil seguito da sc start

Non è l'ideale, ma funziona ...


4

Utilizzare la classe .NET ServiceController per avviarlo o emettere il comando della riga di comando per avviarlo --- "net start servicename". Ad ogni modo funziona.


4

Per aggiungere alla risposta di ScottTx, ecco il codice effettivo per avviare il servizio se lo stai facendo nel modo Microsoft (ad esempio utilizzando un progetto di installazione ecc ...)

(scusa il codice VB.net, ma questo è ciò con cui sono bloccato)

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

Per creare il gestore di eventi di cui sopra, vai al designer ProjectInstaller dove si trovano i 2 controller. Fare clic sul controllo ServiceInstaller1. Vai alla finestra delle proprietà sotto gli eventi e lì troverai l'evento AfterInstall.

Nota: non inserire il codice precedente nell'evento AfterInstall per ServiceProcessInstaller1. Non funzionerà, provenendo dall'esperienza. :)


Il codice VB.net non è male! Per quelli di noi che lavorano in più lingue è bello non dover convertire il codice da C!
Steve Reed Sr

Grazie, questo mi ha aiutato a capire come avviare automaticamente un servizio.
Charles Owen

0

La soluzione più semplice si trova qui install-windows-service-without-installutil-exe di @ 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
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.