Bagaimana cara memulai Layanan Windows .NET tepat setelah penginstalan?

88

Selain service.StartType = ServiceStartMode.Automatic layanan saya tidak dimulai setelah instalasi

Larutan

Kode ini disisipkan di ProjectInstaller saya

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

Terima kasih kepada ScottTx dan Francis B.

Jader Dias
sumber
Itu tidak mulai tepat setelah instalasi atau tidak dimulai saat Anda reboot?
Chris Van Opstal

Jawaban:

21

Anda dapat melakukan ini semua dari dalam layanan Anda yang dapat dieksekusi sebagai respons terhadap peristiwa yang dipicu dari proses InstallUtil. Ganti acara OnAfterInstall untuk menggunakan kelas ServiceController untuk memulai layanan.

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

ScottTx
sumber
3
Ini adalah solusi yang bagus, tetapi masih membutuhkan penggunaan utilitas InstallUtil. Jika Anda sudah mengirimkan InstallUtil sebagai bagian dari instalasi Anda, ini yang paling masuk akal. Namun, jika Anda ingin mengabaikan pengemasan InstallUtil, gunakan solusi baris perintah.
Matt Davis
182

Saya telah memposting prosedur langkah demi langkah untuk membuat layanan Windows di C # di sini . Sepertinya Anda setidaknya sampai pada titik ini, dan sekarang Anda bertanya-tanya bagaimana cara memulai layanan setelah diinstal. Menyetel properti StartType ke Otomatis akan menyebabkan layanan dimulai secara otomatis setelah sistem Anda reboot, tetapi tidak (seperti yang Anda temukan) secara otomatis memulai layanan Anda setelah instalasi.

Saya tidak ingat di mana saya awalnya menemukannya (mungkin Marc Gravell?), Tetapi saya menemukan solusi online yang memungkinkan Anda menginstal dan memulai layanan Anda dengan benar-benar menjalankan layanan Anda sendiri. Inilah langkah demi langkahnya:

  1. Susun Main()fungsi layanan Anda seperti ini:

    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. Berikut kode pendukungnya:

    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. Melanjutkan dengan kode pendukung ...

    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. Pada titik ini, setelah Anda menginstal layanan Anda pada mesin target, jalankan saja layanan Anda dari baris perintah (seperti aplikasi biasa) dengan -installargumen baris perintah untuk menginstal dan memulai layanan Anda.

Saya rasa saya telah membahas semuanya, tetapi jika menurut Anda ini tidak berhasil, beri tahu saya agar saya dapat memperbarui jawabannya.

Matt Davis
sumber
13
Perhatikan bahwa solusi ini tidak memerlukan penggunaan InstallUtil.exe, jadi Anda tidak harus mengirimkannya sebagai bagian dari program penginstalan Anda.
Matt Davis
3
Apa gunanya klausa "catch {throw;}" kosong? Selain itu, mungkin bukan ide yang baik untuk menyembunyikan kegagalan dengan "Rollback ()" karena situasi tersebut pada dasarnya membuat sistem dalam keadaan tidak terdefinisi, saya kira (Anda mencoba menginstal layanan, gagal di suatu tempat di tengah dan tidak dapat membatalkannya ). Anda setidaknya harus "menunjukkan" kepada pengguna bahwa ada sesuatu yang mencurigakan - atau apakah fungsi Rollback () menulis beberapa pesan ke konsol?
Christian.K
5
Rollback tidak menulis data ke konsol. Adapun blok catch yang kosong, itu adalah debugging. Saya bisa meletakkan breakpoint pada pernyataan lemparan untuk memeriksa pengecualian yang mungkin terjadi.
Matt Davis
4
Saya mendapatkan kesalahan Kesalahan: Jenis atau nama namespace 'YourServiceType' tidak dapat ditemukan (apakah Anda melewatkan petunjuk penggunaan atau referensi perakitan?
Yogesh
5
YourServiceTypeadalah yang ProjectInstallerAnda tambahkan ke layanan yang berisi ServiceInstallerdanServiceProcessInstaller
bansi
6

Studio visual

Jika Anda membuat proyek penyiapan dengan VS, Anda dapat membuat tindakan kustom yang disebut metode .NET untuk memulai layanan. Namun, tidak disarankan untuk menggunakan tindakan kustom terkelola di MSI. Lihat halaman ini .

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

Jika Anda menggunakan InstallShield atau Wise, aplikasi ini menyediakan opsi untuk memulai layanan. Misalnya dengan Wise, Anda harus menambahkan tindakan kontrol layanan. Dalam tindakan ini, Anda menentukan apakah Anda ingin memulai atau menghentikan layanan.

Wix

Menggunakan Wix Anda perlu menambahkan kode xml berikut di bawah komponen layanan Anda. Untuk informasi lebih lanjut tentang itu, Anda dapat memeriksa halaman ini .

<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.
sumber
5

Anda perlu menambahkan Tindakan Kustom di akhir urutan 'ExecuteImmediate' di MSI, menggunakan nama komponen EXE atau batch (mulai sc) sebagai sumber. Saya tidak berpikir ini dapat dilakukan dengan Visual Studio, Anda mungkin harus menggunakan alat authoring MSI yang sebenarnya untuk itu.

Otávio Décio
sumber
4

Untuk memulainya tepat setelah instalasi, saya membuat file batch dengan installutil diikuti oleh sc start

Ini tidak ideal, tapi berhasil ....

Matt
sumber
4

Gunakan kelas .NET ServiceController untuk memulainya, atau jalankan perintah baris perintah untuk memulainya --- "nama layanan start bersih". Either way bekerja.

ScottTx
sumber
4

Untuk menambah jawaban ScottTx, berikut kode sebenarnya untuk memulai layanan jika Anda melakukannya dengan cara Microsoft (mis. Menggunakan proyek Setup, dll ...)

(maafkan kode VB.net, tapi ini yang membuat saya terjebak)

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

Untuk membuat pengendali kejadian di atas, buka desainer ProjectInstaller di mana 2 kontrol berada. Klik pada kontrol ServiceInstaller1. Buka jendela properti di bawah acara dan di sana Anda akan menemukan acara AfterInstall.

Catatan: Jangan letakkan kode di atas di bawah event AfterInstall untuk ServiceProcessInstaller1. Itu tidak akan berhasil, datang dari pengalaman. :)

goku_da_master
sumber
Kode VB.net tidak buruk! Bagi kita yang bekerja dalam berbagai bahasa, menyenangkan tidak perlu mengubah kode dari C!
Steve Reed Sr
Terima kasih, ini membantu saya mencari tahu cara memulai layanan secara otomatis.
Charles Owen
0

Solusi termudah ditemukan di sini install-windows-service-without-installutil-exe oleh @ 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
sumber