So erstellen Sie ein Installationsprogramm für einen .net Windows-Dienst mit Visual Studio

Antworten:

227

Gehen Sie im Serviceprojekt wie folgt vor:

  1. Doppelklicken Sie im Solution Explorer auf die CS-Datei Ihrer Services. Es sollte ein grauer Bildschirm angezeigt werden, in dem über das Ziehen von Inhalten aus der Toolbox gesprochen wird.
  2. Klicken Sie dann mit der rechten Maustaste auf den grauen Bereich und wählen Sie Installationsprogramm hinzufügen. Dadurch wird Ihrem Projekt eine Installationsprojektdatei hinzugefügt.
  3. In der Entwurfsansicht von ProjectInstaller.cs befinden sich dann 2 Komponenten (serviceProcessInstaller1 und serviceInstaller1). Anschließend sollten Sie die Eigenschaften nach Bedarf einrichten, z. B. den Dienstnamen und den Benutzer, unter dem sie ausgeführt werden sollen.

Jetzt müssen Sie ein Setup-Projekt erstellen. Verwenden Sie am besten den Setup-Assistenten.

  1. Klicken Sie mit der rechten Maustaste auf Ihre Lösung und fügen Sie ein neues Projekt hinzu: Hinzufügen> Neues Projekt> Setup- und Bereitstellungsprojekte> Setup-Assistent

    ein. Dies kann für verschiedene Versionen von Visual Studio leicht variieren. b. Visual Studio 2010 befindet sich unter: Vorlagen installieren> Andere Projekttypen> Setup und Bereitstellung> Visual Studio Installer

  2. Wählen Sie im zweiten Schritt "Setup für eine Windows-Anwendung erstellen".

  3. Wählen Sie im 3. Schritt "Primäre Ausgabe von ...".

  4. Klicken Sie sich durch, um fertig zu werden.

Bearbeiten Sie als Nächstes Ihr Installationsprogramm, um sicherzustellen, dass die richtige Ausgabe enthalten ist.

  1. Klicken Sie in Ihrem Projektmappen-Explorer mit der rechten Maustaste auf das Setup-Projekt.
  2. Wählen Sie Ansicht> Benutzerdefinierte Aktionen. (In VS2008 ist dies möglicherweise Ansicht> Editor> Benutzerdefinierte Aktionen.)
  3. Klicken Sie mit der rechten Maustaste auf die Aktion "Installieren" in der Struktur "Benutzerdefinierte Aktionen" und wählen Sie "Benutzerdefinierte Aktion hinzufügen ...".
  4. Wählen Sie im Dialogfeld "Element im Projekt auswählen" den Anwendungsordner aus und klicken Sie auf OK.
  5. Klicken Sie auf OK, um die Option "Primäre Ausgabe von ..." auszuwählen. Ein neuer Knoten sollte erstellt werden.
  6. Wiederholen Sie die Schritte 4 bis 5 für Commit-, Rollback- und Deinstallationsaktionen.

Sie können den Namen der Installationsausgabe bearbeiten, indem Sie mit der rechten Maustaste auf das Installationsprojekt in Ihrer Lösung klicken und Eigenschaften auswählen. Ändern Sie den Namen der Ausgabedatei: in einen beliebigen Wert. Durch die Auswahl als auch das Installationsprojekt und suchen Sie in den Eigenschaften - Fenster, können Sie bearbeiten die Product Name, Title, Manufacturerusw ...

Erstellen Sie als Nächstes Ihr Installationsprogramm, und es werden eine MSI und eine setup.exe erstellt. Wählen Sie aus, was Sie zum Bereitstellen Ihres Dienstes verwenden möchten.

Kelsey
quelle
37
@ El Ronnoco, ich hatte die Antwort lange bevor ich gepostet habe. Ich wollte es hier dokumentieren, weil ich es immer alle 6 - 12 Monate nachschlagen muss (und es war nicht so leicht zu finden), also habe ich es jetzt leicht für alle durchsuchbar und kann es selbst schnell finden :)
Kelsey
1
Leider ist es auch die falsche Antwort. Ja, ich weiß, dass Sie dies in Büchern und MSDN finden, aber es ist ein Fall, in dem eine Gruppe in Microsoft nicht mit einer anderen Gruppe in Microsoft gesprochen hat und eine minderwertige Lösung für ein Problem gefunden hat, das bereits gelöst wurde. Weitere Informationen finden Sie unter blog.iswix.com/2006/07/msi-vs-net.html .
Christopher Painter
9
@Christopher Painter Ich benutze das MS-Installationsprogramm seit 2k5 und es hatte nie ein Problem. Ob Sie damit einverstanden sind oder nicht und es als "Anti-Muster" betrachten, ist nicht der Punkt dieser Frage. Es geht darum, wie ich x mit y mache, nicht wie ich a mit b mache. Als ich die Frage stellte, diente sie Dokumentationszwecken.
Kelsey
3
Dann hast du seit 6 Jahren Glück, du weißt es einfach nicht. Vielleicht möchten Sie lesen: robmensching.com/blog/posts/2007/4/19/…
Christopher Painter
1
Wenn Service name contains invalid characters, is empty, or is too long (max length = 80)beim Hinzufügen des Installationsprogramms eine Fehlermeldung angezeigt wird, klicken Sie erneut mit der rechten Maustaste in den grauen Bereich, gehen Sie zu Eigenschaften und stellen Sie sicher, dass der Wert für den Dienstnamen festgelegt ist.
Wolfyuk
51

Ich folge Kelseys ersten Schritten, um die Installationsklassen zu meinem Serviceprojekt hinzuzufügen, aber anstatt ein MSI- oder setup.exe-Installationsprogramm zu erstellen, mache ich den Service selbstinstallierend / deinstallierend. Hier ist ein Beispielcode von einem meiner Dienste, den Sie als Ausgangspunkt verwenden können.

public static int Main(string[] args)
{
    if (System.Environment.UserInteractive)
    {
        // we only care about the first two characters
        string arg = args[0].ToLowerInvariant().Substring(0, 2);

        switch (arg)
        {
            case "/i":  // install
                return InstallService();

            case "/u":  // uninstall
                return UninstallService();

            default:  // unknown option
                Console.WriteLine("Argument not recognized: {0}", args[0]);
                Console.WriteLine(string.Empty);
                DisplayUsage();
                return 1;
        }
    }
    else
    {
        // run as a standard service as we weren't started by a user
        ServiceBase.Run(new CSMessageQueueService());
    }

    return 0;
}

private static int InstallService()
{
    var service = new MyService();

    try
    {
        // perform specific install steps for our queue service.
        service.InstallService();

        // install the service with the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

private static int UninstallService()
{
    var service = new MyQueueService();

    try
    {
        // perform specific uninstall steps for our queue service
        service.UninstallService();

        // uninstall the service from the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service not installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

quelle
1
Was ist aus Neugier der Vorteil eines selbstinstallierenden / deinstallierenden Dienstes? Wenn der Dienst selbst installiert wird, wie starten Sie den Dienst zuerst, damit er überhaupt installiert werden kann? Wenn es einen Mechanismus zum Starten des Dienstes ohne Installation gibt, warum sollte er dann überhaupt installiert werden?
Kiley Naro
3
@ Christopher - ich nicht. Meine Lösung ist kein Ersatz für ein vollständiges Installationsprogramm, mit dem Sie Software verteilen würden. Ich präsentiere eine weitere Option, die in bestimmten Situationen funktioniert, z. B. in meiner, in der ich Software schreibe, die eingebettete PCs in unbeaufsichtigten Kiosken steuert.
4
Denken Sie bei der Installation auf einem Produktionscomputer daran, es als Administrator auszuführen. Ich habe eine BAT-Datei erstellt, die die EXE-Datei mit dem Parameter / i aufruft, aber in der Produktionsumgebung nicht funktioniert, obwohl ich die BAT-Datei als Administrator ausgeführt habe. Ich musste als Administrator eine Eingabeaufforderung öffnen und die EXE-Datei / i explizit aufrufen (ohne die BAT-Datei zu verwenden). Zumindest ist mir das auf einem Windows Server 2012 passiert.
Francisco Goldenstein
1
RE: Keine Ausgabe in der Befehlszeile. Bei Verwendung der VS 2017-Community war mein neues Serviceprojekt standardmäßig Ausgabetyp: Windows Applicationund Startobjekt : (none). Ich musste den Ausgabetyp ändern Console Applicationund mein Startobjekt festlegen, z myservice.Program. Wenn es Konsequenzen gibt, von denen ich nichts weiß, teilen Sie uns dies bitte mit.
Jonathan
1
Hat der Beispielcode Tippfehler? Warum gibt es drei unterschiedliche Dienste (CSMessageQueueService, MyService, MyQueueService)?
Nils Guillermin
27

Weder Kelsey- noch Brendan-Lösungen funktionieren für mich in der Visual Studio 2015-Community nicht.

Hier sind meine kurzen Schritte zum Erstellen eines Dienstes mit dem Installationsprogramm:

  1. Führen Sie Visual Studio aus und gehen Sie zu File->New->Project
  2. Wählen Sie .NET Framework 4 unter "Installierte Vorlagen suchen" aus und geben Sie "Service" ein.
  3. Wählen Sie "Windows-Dienst". Typ Name und Ort. Drücken Sie OK.
  4. Doppelklicken Sie auf Service1.cs, klicken Sie mit der rechten Maustaste in den Designer und wählen Sie "Installer hinzufügen".
  5. Doppelklicken Sie auf ProjectInstaller.cs. Öffnen Sie für serviceProcessInstaller1 die Registerkarte Eigenschaften und ändern Sie den Eigenschaftswert 'Konto' in 'LocalService'. Ändern Sie für serviceInstaller1 'ServiceName' und setzen Sie 'StartType' auf 'Automatic'.
  6. Doppelklicken Sie auf serviceInstaller1. Visual Studio erstellt ein serviceInstaller1_AfterInstallEreignis. Code schreiben:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
    
  7. Lösung erstellen. Klicken Sie mit der rechten Maustaste auf das Projekt und wählen Sie "Ordner im Datei-Explorer öffnen". Gehen Sie zu bin \ Debug .

  8. Erstellen Sie install.bat mit dem folgenden Skript:

    :::::::::::::::::::::::::::::::::::::::::
    :: Automatically check & get admin rights
    :::::::::::::::::::::::::::::::::::::::::
    @echo off
    CLS 
    ECHO.
    ECHO =============================
    ECHO Running Admin shell
    ECHO =============================
    
    :checkPrivileges 
    NET FILE 1>NUL 2>NUL
    if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges ) 
    
    :getPrivileges 
    if '%1'=='ELEV' (shift & goto gotPrivileges)  
    ECHO. 
    ECHO **************************************
    ECHO Invoking UAC for Privilege Escalation 
    ECHO **************************************
    
    setlocal DisableDelayedExpansion
    set "batchPath=%~0"
    setlocal EnableDelayedExpansion
    ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs" 
    ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs" 
    "%temp%\OEgetPrivileges.vbs" 
    exit /B 
    
    :gotPrivileges 
    ::::::::::::::::::::::::::::
    :START
    ::::::::::::::::::::::::::::
    setlocal & pushd .
    
    cd /d %~dp0
    %windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /i "WindowsService1.exe"
    pause
    
  9. Erstellen Sie die Datei uninstall.bat (Änderung in der Zeile pen-ult /iin /u)
  10. Um den Dienst zu installieren und zu starten, führen Sie install.bat aus. Um die Installation zu beenden und zu deinstallieren, führen Sie uninstall.bat aus
Alexey Obukhov
quelle
14

Für VS2017 müssen Sie die VS-Erweiterung "Microsoft Visual Studio 2017 Installer Projects" hinzufügen. Dadurch erhalten Sie zusätzliche Visual Studio Installer-Projektvorlagen. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

Um den Windows-Dienst zu installieren, können Sie ein neues Projekt vom Typ Setup-Assistent hinzufügen und die Schritte aus Kelseys Antwort https://stackoverflow.com/a/9021107/1040040 ausführen

JustSomeDev
quelle
1

InstallUtil-Klassen (ServiceInstaller) werden von der Windows Installer-Community als Anti-Pattern angesehen. Es ist eine fragile, außer Betrieb befindliche Neuerfindung des Rads, die die Tatsache ignoriert, dass Windows Installer integrierte Unterstützung für Dienste bietet.

Visual Studio-Bereitstellungsprojekte (auch in der nächsten Version von Visual Studio nicht hoch angesehen und veraltet) bieten keine native Unterstützung für Dienste. Sie können jedoch Zusammenführungsmodule verbrauchen. Ich würde mir diesen Blog-Artikel ansehen, um zu verstehen, wie ein Zusammenführungsmodul mit Windows Installer XML erstellt wird, das den Dienst ausdrücken und dieses Zusammenführungsmodul dann in Ihrer VDPROJ-Lösung verwenden kann.

Erweitern von InstallShield mithilfe von Windows Installer XML - Windows Services

IsWiX Windows Service Tutorial

IsWiX Windows Service Video

Christopher Maler
quelle
1
Im alten Visual Studio gab es ein Bereitstellungsprojekt mit einem einfachen Erstellungsinstallationsprogramm. Muss ich jetzt Softwarekomponenten von Drittanbietern kaufen?
Alexey Obukhov
@AlexeyObukhov Sie können Wix kostenlos verwenden, das verwendet VS selbst, aber das Problem mit Wix ist das gleiche wie das Problem mit Git - der nahezu vertikalen Lernkurve.
Alan B