วิธีการสร้างโปรแกรมติดตั้งสำหรับ. net Windows Service โดยใช้ Visual Studio


152

ฉันจะสร้างตัวติดตั้งสำหรับบริการ Windows ที่ฉันสร้างขึ้นโดยใช้ Visual Studio ได้อย่างไร


นี่มีการบันทึกไว้แล้วในบทความ Microsoft KB ต่อไปนี้: support.microsoft.com/en-us/kb/816169
slayernoah

คำตอบ:


227

ในโครงการบริการให้ทำดังต่อไปนี้:

  1. ใน Explorer โซลูชันดับเบิลคลิกไฟล์. cs บริการของคุณ ควรแสดงหน้าจอที่เป็นสีเทาทั้งหมดและพูดถึงการลากสิ่งต่าง ๆ จากกล่องเครื่องมือ
  2. จากนั้นคลิกขวาบนพื้นที่สีเทาและเลือกเพิ่มตัวติดตั้ง สิ่งนี้จะเพิ่มไฟล์โครงการตัวติดตั้งลงในโครงการของคุณ
  3. จากนั้นคุณจะมี 2 องค์ประกอบในมุมมองออกแบบของ ProjectInstaller.cs (serviceProcessInstaller1 และ serviceInstaller1) จากนั้นคุณควรตั้งค่าคุณสมบัติตามที่คุณต้องการเช่นชื่อบริการและผู้ใช้ที่ควรรัน

ตอนนี้คุณต้องสร้างโครงการติดตั้ง สิ่งที่ดีที่สุดที่ต้องทำคือใช้ตัวช่วยการตั้งค่า

  1. คลิกขวาที่โซลูชันของคุณและเพิ่มโครงการใหม่: เพิ่ม> โครงการใหม่> โครงการติดตั้งและปรับใช้> ตัวช่วยสร้างการติดตั้ง

    สิ่งนี้อาจแตกต่างกันเล็กน้อยสำหรับ Visual Studio รุ่นต่างๆ ข Visual Studio 2010 ตั้งอยู่ใน: ติดตั้งแม่แบบ> ประเภทโครงการอื่น ๆ > การติดตั้งและการปรับใช้> ตัวติดตั้ง Studio Visual

  2. ในขั้นตอนที่สองเลือก "สร้างการตั้งค่าสำหรับแอปพลิเคชัน Windows"

  3. ในขั้นตอนที่ 3 เลือก "เอาต์พุตหลักจาก ... "

  4. คลิกผ่านเพื่อเสร็จสิ้น

แก้ไขตัวติดตั้งของคุณต่อไปเพื่อให้แน่ใจว่ามีการรวมเอาท์พุทที่ถูกต้อง

  1. คลิกขวาที่โครงการติดตั้งใน Solution Explorer ของคุณ
  2. เลือกมุมมอง> การกระทำที่กำหนดเอง (ใน VS2008 อาจเป็น View> Editor> Custom Actions)
  3. คลิกขวาที่แอคชั่นติดตั้งในทรีแอคชั่นที่กำหนดเองและเลือก 'เพิ่มการกระทำที่กำหนดเอง ...
  4. ในกล่องโต้ตอบ "เลือกรายการในโครงการ" ให้เลือกโฟลเดอร์แอปพลิเคชันแล้วคลิกตกลง
  5. คลิกตกลงเพื่อเลือกตัวเลือก "เอาต์พุตหลักจาก ... " ควรสร้างโหนดใหม่
  6. ทำซ้ำขั้นตอนที่ 4 - 5 สำหรับการกระทำกระทำย้อนกลับและถอนการติดตั้ง

คุณสามารถแก้ไขชื่อเอาต์พุตของตัวติดตั้งได้โดยคลิกขวาที่โครงการตัวติดตั้งในโซลูชันของคุณและเลือกคุณสมบัติ เปลี่ยน 'ชื่อไฟล์เอาต์พุต:' เป็นสิ่งที่คุณต้องการ โดยการเลือกโครงการติดตั้งเป็นอย่างดีและมองไปที่หน้าต่างคุณสมบัติคุณสามารถแก้ไขProduct Name, Title, Manufacturerฯลฯ ...

ถัดไปสร้างตัวติดตั้งของคุณและมันจะสร้าง MSI และ setup.exe เลือกสิ่งที่คุณต้องการใช้เพื่อปรับใช้บริการของคุณ


37
@El Ronnoco ฉันมีคำตอบนานก่อนที่จะโพสต์ ฉันต้องการจัดทำเอกสารที่นี่เพราะฉันมักจะต้องค้นหามันทุก ๆ 6 - 12 เดือน (และมันก็ไม่ง่ายที่จะหา) ดังนั้นตอนนี้ฉันจึงสามารถค้นหาได้ง่ายสำหรับทุกคนและฉันสามารถค้นพบตัวเองได้อย่างรวดเร็ว :)
Kelsey

1
โชคไม่ดีที่มันเป็นคำตอบที่ผิด ใช่ฉันรู้ว่าคุณจะพบสิ่งนี้ในหนังสือและ MSDN แต่เป็นกรณีที่กลุ่มหนึ่งใน Microsoft ไม่ได้พูดคุยกับกลุ่มอื่นใน Microsoft และมาพร้อมวิธีแก้ปัญหาที่ด้อยกว่าสำหรับปัญหาที่ได้รับการแก้ไขแล้ว ดูblog.iswix.com/2006/07/msi-vs-net.htmlสำหรับข้อมูลเพิ่มเติม
Christopher Painter

9
@Christopher Painter ฉันใช้ MS installer มาตั้งแต่ 2k5 และมันไม่เคยมีปัญหา ไม่ว่าคุณจะเห็นด้วยหรือไม่และพิจารณาว่า 'รูปแบบการต่อต้าน' ไม่ใช่ประเด็นของคำถามนี้มันเป็นวิธีที่ฉันจะทำ x กับ y ไม่ใช่ว่าฉันจะทำอย่างไรกับ b เมื่อฉันโพสต์คำถามนั้นมีวัตถุประสงค์เพื่อเป็นเอกสารประกอบ
Kelsey

3
ถ้าอย่างนั้นคุณก็โชคดีมา 6 ปีแล้วคุณก็ไม่รู้เหมือนกัน คุณอาจต้องการอ่าน: robmensching.com/blog/posts/2007/4/19/…
Christopher Painter

1
หากคุณได้รับService name contains invalid characters, is empty, or is too long (max length = 80)ข้อผิดพลาดเมื่อเพิ่มตัวติดตั้งให้คลิกขวาในพื้นที่สีเทาอีกครั้งไปที่คุณสมบัติและตรวจสอบให้แน่ใจว่าได้ตั้งค่าชื่อบริการแล้ว
wolfyuk

51

ฉันทำตามขั้นตอนชุดแรกของ Kelsey เพื่อเพิ่มคลาสตัวติดตั้งในโครงการบริการของฉัน แต่แทนที่จะสร้างตัวติดตั้ง MSI หรือ setup.exe ฉันจะทำให้บริการติดตั้ง / ถอนการติดตั้งด้วยตนเอง นี่คือตัวอย่างโค้ดจากบริการของฉันที่คุณสามารถใช้เป็นจุดเริ่มต้น

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

1
จากความอยากรู้สิ่งที่เป็นประโยชน์ในการมีบริการติดตั้งด้วยตนเอง / ยกเลิกการติดตั้ง? หากบริการติดตั้งตัวเองคุณจะเริ่มบริการได้อย่างไรก่อนเพื่อให้สามารถติดตั้งได้ตั้งแต่แรก หากมีกลไกในการเริ่มบริการโดยไม่ต้องทำการติดตั้งทำไมต้องติดตั้งเลย
Kiley Naro

3
@Christopher - ฉันทำไม่ได้ โซลูชันของฉันไม่ได้ใช้แทนโปรแกรมติดตั้งเต็มรูปแบบที่คุณจะใช้เพื่อแจกจ่ายซอฟต์แวร์ ฉันกำลังนำเสนอตัวเลือกอื่นที่ใช้งานได้ในบางสถานการณ์เช่นของฉันที่ฉันเขียนซอฟต์แวร์ที่ทำให้พีซีแบบฝังตัวอยู่ในซุ้มแบบอัตโนมัติ

4
เมื่อคุณติดตั้งบนเครื่องที่ใช้งานจริงอย่าลืมเรียกใช้ในฐานะผู้ดูแลระบบ ฉันสร้างไฟล์ BAT ที่เรียกใช้ไฟล์ EXE ด้วยพารามิเตอร์ / i แต่ไม่ได้ทำงานในสภาพแวดล้อมการผลิตแม้ว่าฉันจะเรียกใช้ไฟล์ BAT ในฐานะผู้ดูแลระบบ ฉันต้องเปิดพรอมต์บรรทัดคำสั่งในฐานะผู้ดูแลระบบและเรียกใช้ไฟล์ EXE / i อย่างชัดเจน (โดยไม่ใช้ไฟล์ BAT) อย่างน้อยก็เกิดกับฉันใน Windows Server 2012
Francisco Goldenstein

1
RE: ไม่มีเอาต์พุตบน Command Line การใช้ VS 2017 ชุมชนโครงการบริการใหม่ของฉันผิดนัดประเภทขาออกและเริ่มต้นวัตถุ:Windows Application (none)ผมมีการเปลี่ยนแปลงประเภทเอาท์พุทและการตั้งค่าของฉันเช่นวัตถุเริ่มต้นConsole Application myservice.Programหากอาจมีการแตกหักซึ่งฉันไม่ทราบโปรดแจ้ง
Jonathan

1
โค้ดตัวอย่างมีตัวพิมพ์ผิดหรือไม่? เหตุใดจึงมีบริการแตกต่างกันสามบริการ (CSMessageQueueService, MyService, MyQueueService)
Nils Guillermin

27

Nor Kelsey และโซลูชันของ Brendan ไม่ได้ผลสำหรับฉันในชุมชน Visual Studio 2015

นี่คือขั้นตอนสั้น ๆ ของฉันวิธีการสร้างบริการด้วยตัวติดตั้ง:

  1. เรียกใช้ Visual Studio ไปที่ File->New->Project
  2. เลือก. NET Framework 4 ใน 'ค้นหาเทมเพลตที่ติดตั้ง' ประเภท'บริการ'
  3. เลือก 'บริการ Windows' พิมพ์ชื่อและที่ตั้ง OKกด
  4. ดับเบิลคลิกที่ Service1.cs คลิกขวาที่ตัวออกแบบและเลือก 'เพิ่มโปรแกรมติดตั้ง'
  5. ดับเบิลคลิก ProjectInstaller.cs สำหรับ serviceProcessInstaller1 เปิดคุณสมบัติแท็บและเปลี่ยนค่าคุณสมบัติ 'บัญชี' เป็น 'LocalService' สำหรับ serviceInstaller1 เปลี่ยน 'ServiceName' และตั้ง 'StartType' เป็น 'อัตโนมัติ'
  6. ดับเบิลคลิก serviceInstaller1 Visual Studio สร้างserviceInstaller1_AfterInstallกิจกรรม เขียนรหัส:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
    
  7. สร้างโซลูชัน คลิกขวาที่โครงการและเลือก 'เปิดโฟลเดอร์ใน File Explorer' ไปที่bin \ Debug

  8. สร้าง install.bat ด้วยสคริปต์ด้านล่าง:

    :::::::::::::::::::::::::::::::::::::::::
    :: 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. สร้างไฟล์ uninstall.bat (เปลี่ยนเป็น pen-ult line /iเป็น/u)
  10. ในการติดตั้งและเริ่มให้บริการรัน install.bat เพื่อหยุดและถอนการติดตั้งให้รัน uninstall.bat

14

สำหรับ VS2017 คุณจะต้องเพิ่มส่วนขยาย VS "Microsoft Visual Studio 2017 โครงการ" สิ่งนี้จะให้แม่แบบโครงการ Visual Studio Installer เพิ่มเติมให้คุณ https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

ในการติดตั้งบริการ windows คุณสามารถเพิ่มโครงการประเภทวิซาร์ดการตั้งค่าใหม่และทำตามขั้นตอนจากคำตอบของ Kelsey https://stackoverflow.com/a/9021107/1040040


1

คลาส InstallUtil (ServiceInstaller) ถือเป็นรูปแบบการต่อต้านโดยชุมชน Windows Installer มันเป็นกระบวนการที่ไม่เปราะบางการคิดค้นล้อที่ไม่สนใจข้อเท็จจริงที่ว่า Windows Installer มีการรองรับบริการในตัว

โครงการปรับใช้ Visual Studio (ยังไม่ได้รับการยอมรับและคัดค้านอย่างมากใน Visual Studio รุ่นถัดไป) ไม่มีการสนับสนุนดั้งเดิมสำหรับบริการ แต่พวกเขาสามารถใช้โมดูลผสาน ดังนั้นฉันจะดูที่บทความบล็อกนี้เพื่อทำความเข้าใจวิธีสร้างโมดูลผสานโดยใช้ Windows Installer XML ที่สามารถแสดงบริการแล้วใช้โมดูลผสานนั้นในโซลูชัน VDPROJ ของคุณ

การขยาย InstallShield โดยใช้ Windows Installer XML - บริการ Windows

บทแนะนำบริการ IsWiX ของ Windows

วิดีโอบริการ Windows ของ IsWiX


1
ใน Visual Studio เก่ามีโครงการปรับใช้พร้อมตัวติดตั้งการสร้างที่ง่าย ตอนนี้ฉันต้องซื้อส่วนประกอบซอฟต์แวร์บุคคลที่สามหรือไม่
Alexey Obukhov

@AlexeyObukhov คุณสามารถใช้ Wix ได้ฟรีนั่นเป็นสิ่งที่ VS ใช้เอง แต่ปัญหาของ Wix นั้นเหมือนกับปัญหาของ Git ซึ่งเป็นกราฟการเรียนรู้ในแนวดิ่งใกล้เคียง
Alan B
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.