Jak uruchomić usługę .NET Windows zaraz po instalacji?

88

Oprócz service.StartType = ServiceStartMode.Automatic moja usługa nie uruchamia się po instalacji

Rozwiązanie

Wstawiłem ten kod do mojego ProjectInstaller

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

Dzięki ScottTx i Francis B.

Jader Dias
źródło
Nie uruchamia się zaraz po instalacji lub nie uruchamia się po ponownym uruchomieniu?
Chris Van Opstal

Odpowiedzi:

21

Możesz to wszystko zrobić z poziomu pliku wykonywalnego usługi w odpowiedzi na zdarzenia wywołane z procesu InstallUtil. Zastąp zdarzenie OnAfterInstall, aby użyć klasy ServiceController do uruchomienia usługi.

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

ScottTx
źródło
3
To fajne rozwiązanie, ale nadal wymaga użycia narzędzia InstallUtil. Jeśli już dostarczasz InstallUtil jako część swojej instalacji, ma to największy sens. Jeśli jednak chcesz zrezygnować z pakowania InstallUtil, użyj rozwiązania wiersza polecenia.
Matt Davis
181

Mam napisali procedurę krok po kroku do tworzenia usługi Windows w C # tutaj . Wygląda na to, że jesteś przynajmniej do tego momentu, a teraz zastanawiasz się, jak uruchomić usługę po jej zainstalowaniu. Ustawienie właściwości StartType na Automatic spowoduje automatyczne uruchomienie usługi po ponownym uruchomieniu systemu, ale nie (jak odkryłeś) automatycznie uruchomi usługę po instalacji.

Nie pamiętam, gdzie go pierwotnie znalazłem (być może Marc Gravell?), Ale znalazłem w Internecie rozwiązanie, które umożliwia zainstalowanie i uruchomienie usługi poprzez faktyczne jej uruchomienie. Oto krok po kroku:

  1. Zorganizuj Main()funkcję swojej usługi w następujący sposób:

    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. Oto kod pomocniczy:

    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. Kontynuując kod pomocniczy ...

    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. W tym momencie, po zainstalowaniu usługi na maszynie docelowej, po prostu uruchom ją z wiersza poleceń (jak każda zwykła aplikacja) z -installargumentem wiersza poleceń, aby zainstalować i uruchomić usługę.

Myślę, że omówiłem wszystko, ale jeśli okaże się, że to nie działa, daj mi znać, abym mógł zaktualizować odpowiedź.

Matt Davis
źródło
12
Zwróć uwagę, że to rozwiązanie nie wymaga użycia programu InstallUtil.exe, więc nie musisz dostarczać go jako części programu instalacyjnego.
Matt Davis,
3
O co chodzi z pustymi klauzulami "catch {throw;}"? Poza tym prawdopodobnie nie jest dobrym pomysłem ukrywanie awarii za pomocą funkcji "Rollback ()" ponieważ ta sytuacja w zasadzie pozostawia system w nieokreślonym stanie (próbowałeś zainstalować usługę, gdzieś pośrodku się nie udało i nie mogłeś tego cofnąć ). Powinieneś przynajmniej „pokazać” użytkownikowi, że jest coś podejrzanego - czy też funkcja Rollback () zapisuje jakieś komunikaty do konsoli?
Christian.K
5
Wycofywanie nie zapisuje danych w konsoli. Jeśli chodzi o puste bloki catch, jest to kwestia debugowania. Mogę umieścić punkt przerwania w instrukcji throw, aby zbadać ewentualne wyjątki.
Matt Davis,
4
Otrzymuję błąd Błąd: Nie można znaleźć nazwy typu lub przestrzeni nazw „YourServiceType” (czy brakuje dyrektywy using lub odwołania do zestawu?
Yogesh
5
YourServiceTypejest tym, ProjectInstallerktóry dodałeś do usługi, która zawiera ServiceInstalleriServiceProcessInstaller
bansi
6

Visual Studio

Jeśli tworzysz projekt instalacyjny za pomocą VS, możesz utworzyć akcję niestandardową, która wywołała metodę .NET w celu uruchomienia usługi. Ale tak naprawdę nie jest zalecane używanie zarządzanej akcji niestandardowej w MSI. Zobacz tę stronę .

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

Jeśli używasz InstallShield lub Wise, te aplikacje zapewniają opcję uruchomienia usługi. Na przykład w przypadku Wise musisz dodać akcję kontroli usługi. W tej akcji określasz, czy chcesz uruchomić, czy zatrzymać usługę.

Wix

Korzystając z Wix, musisz dodać następujący kod xml pod komponentem swojej usługi. Więcej informacji na ten temat można znaleźć na tej stronie .

<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.
źródło
5

Musisz dodać akcję niestandardową na końcu sekwencji „ExecuteImmediate” w pliku MSI, używając nazwy komponentu EXE lub partii (start sc) jako źródła. Nie sądzę, aby można to zrobić w programie Visual Studio, być może będziesz musiał użyć do tego prawdziwego narzędzia autorskiego MSI.

Otávio Décio
źródło
4

Aby uruchomić go zaraz po instalacji, generuję plik wsadowy z installutil, a następnie sc start

Nie jest idealny, ale działa ....

Matt
źródło
4

Użyj klasy .NET ServiceController, aby ją uruchomić, lub wydaj polecenie wiersza polecenia, aby ją uruchomić - „net start nazwa usługi”. Tak czy inaczej działa.

ScottTx
źródło
4

Aby dodać do odpowiedzi ScottTx, oto rzeczywisty kod uruchamiający usługę, jeśli robisz to w sposób Microsoft (tj. Używając projektu instalacyjnego itp.)

(przepraszam za kod VB.net, ale na tym utknąłem)

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

Aby utworzyć powyższą procedurę obsługi zdarzeń, przejdź do projektanta ProjectInstaller, w którym znajdują się 2 kontrolery. Kliknij formant ServiceInstaller1. Przejdź do okna właściwości pod zdarzeniami, a tam znajdziesz zdarzenie AfterInstall.

Uwaga: nie umieszczaj powyższego kodu w zdarzeniu AfterInstall dla ServiceProcessInstaller1. To nie zadziała, biorąc pod uwagę doświadczenie. :)

goku_da_master
źródło
Kod VB.net nie jest zły! Dla tych z nas, którzy pracują w wielu językach, miło jest nie konwertować kodu z C!
Steve Reed Sr
Dzięki, to pomogło mi dowiedzieć się, jak automatycznie uruchomić usługę.
Charles Owen
0

Najłatwiejsze rozwiązanie można znaleźć tutaj install-windows-service-without-installutil-exe autorstwa @ 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
źródło