Jak utworzyć instalator usługi .net systemu Windows przy użyciu programu Visual Studio

Odpowiedzi:

227

W projekcie usługi wykonaj następujące czynności:

  1. W eksploratorze rozwiązań kliknij dwukrotnie plik .cs usług. Powinien wyświetlić ekran, który jest cały szary i mówi o przeciąganiu rzeczy z przybornika.
  2. Następnie kliknij prawym przyciskiem myszy szary obszar i wybierz dodaj instalator. Spowoduje to dodanie pliku projektu instalatora do twojego projektu.
  3. Następnie będziesz mieć 2 komponenty w widoku projektu ProjectInstaller.cs (serviceProcessInstaller1 i serviceInstaller1). Następnie należy skonfigurować wymagane właściwości, takie jak nazwa usługi i użytkownik, jako którego ma działać.

Teraz musisz wykonać projekt konfiguracji. Najlepszą rzeczą do zrobienia jest skorzystanie z kreatora konfiguracji.

  1. Kliknij prawym przyciskiem myszy rozwiązanie i dodaj nowy projekt: Dodaj> Nowy projekt> Projekty konfiguracji i wdrażania> Kreator instalacji

    za. Może się to nieznacznie różnić w przypadku różnych wersji programu Visual Studio. b. Visual Studio 2010 znajduje się w: Zainstaluj szablony> Inne typy projektów> Konfiguracja i wdrażanie> Instalator programu Visual Studio

  2. W drugim kroku wybierz „Utwórz konfigurację aplikacji dla systemu Windows”.

  3. W trzecim kroku wybierz „Wyjście podstawowe z ...”

  4. Kliknij, aby zakończyć.

Następnie wyedytuj instalator, aby upewnić się, że zawiera poprawne wyjście.

  1. Kliknij prawym przyciskiem myszy projekt instalacji w Eksploratorze rozwiązań.
  2. Wybierz Widok> Akcje niestandardowe. (W VS2008 może to być Widok> Edytor> Akcje niestandardowe)
  3. Kliknij prawym przyciskiem myszy czynność Instaluj w drzewie akcji niestandardowych i wybierz opcję „Dodaj akcję niestandardową ...”
  4. W oknie dialogowym „Wybierz element w projekcie” wybierz opcję Folder aplikacji i kliknij przycisk OK.
  5. Kliknij przycisk OK, aby wybrać opcję „Podstawowe wyjście z ...”. Powinien zostać utworzony nowy węzeł.
  6. Powtórz kroki 4-5 dla akcji zatwierdzania, wycofywania i odinstalowywania.

Możesz edytować nazwę wyjściową instalatora, klikając prawym przyciskiem myszy projekt Instalatora w rozwiązaniu i wybierając opcję Właściwości. Zmień „Nazwę pliku wyjściowego:” na dowolną. Po wybraniu projektu instalatora, jak również i patrząc w okna właściwości można edytować Product Name, Title, Manufacturer, itd ...

Następnie skompiluj instalator, który utworzy plik MSI i plik setup.exe. Wybierz dowolną, której chcesz użyć do wdrożenia usługi.

Kelsey
źródło
37
@El Ronnoco, otrzymałem odpowiedź na długo przed opublikowaniem. Chciałem to tutaj udokumentować, ponieważ zawsze muszę to sprawdzać co 6-12 miesięcy (i nie było to łatwe do znalezienia), więc teraz mam to łatwe do wyszukania dla wszystkich i mogę to szybko znaleźć :)
Kelsey
1
Niestety, to także zła odpowiedź. Tak, wiem, że znajdziesz to w książkach i MSDN, ale jest to przypadek, w którym jedna grupa w Microsoft nie rozmawiała z inną grupą w Microsoft i wymyśliła gorsze rozwiązanie problemu, który został już rozwiązany. Aby uzyskać więcej informacji, zobacz blog.iswix.com/2006/07/msi-vs-net.html .
Christopher Painter,
9
@Christopher Painter Używam instalatora MS od 2k5 i nigdy nie miałem problemu. To, czy się z tym zgadzasz i uważasz to za „anty-wzór”, nie jest celem tego pytania, chodzi o to, jak mam zrobić x z y, a nie jak zrobić a z b. Kiedy wysłałem pytanie, było to w celach dokumentacyjnych.
Kelsey
3
Potem przez 6 lat miałeś szczęście, po prostu o tym nie wiesz. Możesz przeczytać: robmensching.com/blog/posts/2007/4/19/ ...
Christopher Painter
1
Jeśli Service name contains invalid characters, is empty, or is too long (max length = 80)podczas dodawania Instalatora pojawi się błąd, kliknij ponownie prawym przyciskiem myszy w szarym obszarze, przejdź do Właściwości i upewnij się, że ustawiona jest wartość Nazwa usługi.
wolfyuk
51

Postępuję zgodnie z pierwszym zestawem kroków Kelsey, aby dodać klasy instalatora do mojego projektu usługi, ale zamiast tworzyć instalator MSI lub setup.exe, wykonuję usługę samoczynnie instalując / odinstalowując. Oto fragment przykładowego kodu z jednej z moich usług, którego możesz użyć jako punktu wyjścia.

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

źródło
1
Z ciekawości, jakie są korzyści z posiadania usługi samodzielnej instalacji / odinstalowania? Jeśli usługa instaluje się sama, jak uruchomić usługę jako pierwszą, aby można ją było zainstalować w pierwszej kolejności? Jeśli istnieje mechanizm uruchamiania usługi bez jej instalowania, po co w ogóle go instalować?
Kiley Naro
3
@Christopher - ja nie. Moje rozwiązanie nie zastępuje pełnego instalatora, którego używałbyś do dystrybucji oprogramowania. Przedstawiam inną opcję, która działa w niektórych sytuacjach, na przykład w mojej, w której piszę oprogramowanie, które napędza wbudowane komputery w kioskach bez nadzoru.
4
Podczas instalowania go na maszynie produkcyjnej pamiętaj, aby uruchomić go jako administrator. Utworzyłem plik BAT, który wywołuje plik EXE z parametrem / i, ale nie działał w środowisku produkcyjnym, mimo że wykonałem plik BAT jako administrator. Jako administrator musiałem otworzyć wiersz poleceń i jawnie wywołać plik EXE / i (bez użycia pliku BAT). Przynajmniej zdarzyło mi się to na Windows Server 2012.
Francisco Goldenstein
1
RE: Brak danych wyjściowych w wierszu poleceń. Korzystanie z VS 2017 Wspólnotę mój nowy projekt usługa domyślnie Typ wyjścia: Windows Applicationa przedmiotem Startup: (none). Musiałem zmienić typ wyjścia na Console Applicationi ustawić mój obiekt startowy np myservice.Program. Jeśli mogą istnieć konsekwencje, których nie jestem świadomy, proszę o poradę.
Jonathan
1
Czy przykładowy kod zawiera literówki? Dlaczego istnieją trzy różne usługi (CSMessageQueueService, MyService, MyQueueService)?
Nils Guillermin
27

Ani rozwiązania Kelsey, ani Brendan nie działają dla mnie w społeczności Visual Studio 2015.

Oto moje krótkie kroki, jak utworzyć usługę za pomocą instalatora:

  1. Uruchom program Visual Studio, przejdź do File->New->Project
  2. Wybierz .NET Framework 4, w polu „Wyszukaj zainstalowane szablony” wpisz „Usługa”
  3. Wybierz opcję „Usługa systemu Windows”. Wpisz nazwę i lokalizację. Naciśnij OK.
  4. Kliknij dwukrotnie Service1.cs, kliknij prawym przyciskiem myszy w projektancie i wybierz „Dodaj instalator”
  5. Kliknij dwukrotnie ProjectInstaller.cs. W przypadku serviceProcessInstaller1 otwórz kartę Właściwości i zmień wartość właściwości „Konto” na „Usługa lokalna”. W przypadku serviceInstaller1 zmień „ServiceName” i ustaw „StartType” na „Automatyczny”.
  6. Kliknij dwukrotnie serviceInstaller1. Visual Studio tworzy serviceInstaller1_AfterInstallzdarzenie. Wpisz kod:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
    
  7. Zbuduj rozwiązanie. Kliknij prawym przyciskiem myszy projekt i wybierz „Otwórz folder w Eksploratorze plików”. Przejdź do bin \ Debug .

  8. Utwórz plik install.bat z poniższym skryptem:

    :::::::::::::::::::::::::::::::::::::::::
    :: 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. Utwórz plik uninstall.bat (zmień linię pen-ult /ina /u)
  10. Aby zainstalować i uruchomić usługę, uruchom install.bat, aby zatrzymać i odinstalować, uruchom uninstall.bat
Alexey Obukhov
źródło
14

W przypadku VS2017 należy dodać rozszerzenie VS „Projekty instalatora Microsoft Visual Studio 2017”. Zapewni to dodatkowe szablony projektów Instalatora programu Visual Studio. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

Aby zainstalować usługę Windows, możesz dodać nowy projekt typu kreatora konfiguracji i postępować zgodnie z instrukcjami zawartymi w odpowiedzi Kelsey https://stackoverflow.com/a/9021107/1040040

JustSomeDev
źródło
1

Klasy InstallUtil (ServiceInstaller) są uważane przez społeczność Instalatorów Windows za anty-wzorzec. Jest to kruche wymyślenie na nowo koła, które ignoruje fakt, że Instalator Windows ma wbudowaną obsługę usług.

Projekty wdrożeniowe programu Visual Studio (również niezbyt cenione i przestarzałe w następnej wersji programu Visual Studio) nie mają natywnej obsługi usług. Ale mogą zużywać moduły scalające. Dlatego chciałbym rzucić okiem na ten artykuł na blogu, aby zrozumieć, jak utworzyć moduł scalający za pomocą pliku XML Instalatora Windows, który może wyrazić usługę, a następnie wykorzystać ten moduł scalający w rozwiązaniu VDPROJ.

Rozszerzanie programu InstallShield przy użyciu programu Windows Installer XML - usługi Windows

Samouczek dotyczący usług systemu Windows IsWiX

Wideo usługi IsWiX Windows

Christopher Painter
źródło
1
W starym programie Visual Studio istniał projekt wdrożeniowy z łatwym instalatorem do tworzenia. Teraz muszę kupić komponent oprogramowania innej firmy?
Alexey Obukhov
@AlexeyObukhov Możesz używać Wix za darmo, właśnie tego używa VS, ale problem z Wix jest taki sam jak problem z Git - prawie pionowa krzywa uczenia się.
Alan B