Windows hizmeti olarak .NET konsol uygulaması


145

Konsol uygulamam var ve Windows hizmeti olarak çalıştırmak istiyorum. VS2010 konsol projesi eklemek ve Windows hizmeti oluşturmak için izin proje şablonu vardır. Ayrılmış hizmet projesi eklemek istemiyor ve mümkünse, konsol uygulamasını konsol uygulaması olarak çalıştırabilecek bir uygulama olarak veya örneğin anahtarları kullanarak komut satırından çalıştırıldığında windows hizmeti olarak tutmak için hizmet kodunu konsol uygulamasına entegre etmek istiyorum.

Belki birisi hızlı ve kolay c # konsol uygulaması hizmet dönüştürebilirsiniz sınıf kitaplığı veya kod snippet önerebilir?


Neden sadece geçici bir hizmet projesi oluşturmuyorsunuz ve onu bir hizmet haline getiren bitleri kopyalamıyorsunuz?
Gabe

4
Topshelf'i deneyebilirsiniz topshelf-project.com
Artem Koshelev

Burada açıklanan tekniği deneyebilirsiniz: einaregilsson.com/2007/08/15/…
Joe

ha? Emin değilim. bunun hakkında.

2
Çok basit bir üst raf alternatifi: runasservice.com
Luis Perez

Yanıtlar:


186

Bir konsol uygulaması veya hizmet olarak aynı uygulamayı çalıştırmak için genellikle aşağıdaki tekniği kullanırım:

public static class Program
{
    #region Nested classes to support running as service
    public const string ServiceName = "MyService";

    public class Service : ServiceBase
    {
        public Service()
        {
            ServiceName = Program.ServiceName;
        }

        protected override void OnStart(string[] args)
        {
            Program.Start(args);
        }

        protected override void OnStop()
        {
            Program.Stop();
        }
    }
    #endregion

    static void Main(string[] args)
    {
        if (!Environment.UserInteractive)
            // running as service
            using (var service = new Service())
                ServiceBase.Run(service);
        else
        {
            // running as console app
            Start(args);

            Console.WriteLine("Press any key to stop...");
            Console.ReadKey(true);

            Stop();
        }
    }

    private static void Start(string[] args)
    {
        // onstart code here
    }

    private static void Stop()
    {
        // onstop code here
    }
}

Environment.UserInteractivenormalde konsol uygulaması için doğrudur ve bir hizmet için yanlıştır. Teknik olarak, bir servisi kullanıcı etkileşimli modda çalıştırmak mümkündür, böylece bunun yerine bir komut satırı anahtarını kontrol edebilirsiniz.


3
ServiceInstaller sınıfını kullanırsınız, bkz. Msdn.microsoft.com/en-us/library/… .
VladV

2
Bu beklenen bir durumdur - hizmetiniz ayrı bir işlem olarak çalışır (bu nedenle görev yöneticisinde gösterilir), ancak bu işlem sistem tarafından kontrol edilir (örn. Başlatıldı, durduruldu, servis ayarlarına göre yeniden başlatıldı).
VladV

2
Konsol uygulaması olarak çalıştırırsanız, bir hizmet görmezsiniz. Bu kodun amacı, onu bir konsol uygulaması olarak veya bir hizmet olarak çalıştırmanızı sağlamaktır. Bir hizmet olarak çalıştırmak için önce (ServiceInstaller sınıfını kullanarak - yukarıdaki MSDN bağlantısına bakın - veya installuitil.exe'yi) yüklemeniz ve hizmeti kontrol panelinden çalıştırmanız gerekir.
VladV

2
ServiceInstaller sadece Windows hizmetleri (biraz installutil.exe veya sc.exe yardımcı programları gibi) ile başa çıkmak için bir yardımcı sınıftır. Hizmet olarak istediğinizi yüklemek için kullanabilirsiniz, işletim sistemi kullandığınız proje türünü önemsemez.
VladV

5
Projenize System.ServiceProcess'e bir referans eklemeniz yeterlidir ve yukarıdaki kodu kullanabilirsiniz
danimal

59

TopShelf ile büyük başarı elde ettim .

TopShelf, konsol uygulamaları veya Windows Hizmetleri olarak çalışabilen .NET Windows uygulamaları oluşturmayı kolaylaştırmak için tasarlanmış bir Nuget paketidir. Hizmet Start ve Stop olayları gibi olayları hızlı bir şekilde bağlayabilir, örneğin çalıştığı hesabı ayarlamak için kod kullanarak yapılandırabilir, diğer servislere bağımlılıkları yapılandırabilir ve hatalardan nasıl kurtarılacağını yapılandırabilirsiniz.

Paket Yöneticisi Konsolu'ndan (Nuget):

Kurulum Paketi Topshelf

Başlamak için kod örneklerine bakın .

Misal:

HostFactory.Run(x =>                                 
{
    x.Service<TownCrier>(s =>                        
    {
       s.ConstructUsing(name=> new TownCrier());     
       s.WhenStarted(tc => tc.Start());              
       s.WhenStopped(tc => tc.Stop());               
    });
    x.RunAsLocalSystem();                            

    x.SetDescription("Sample Topshelf Host");        
    x.SetDisplayName("Stuff");                       
    x.SetServiceName("stuff");                       
}); 

TopShelf ayrıca çok zaman kazandıracak ve çözüm plakasını çözümünüzden kaldıran servis kurulumuyla da ilgilenir. .Exe'inizi bir hizmet olarak yüklemek için komut isteminde aşağıdakileri uygulamanız yeterlidir:

myservice.exe install -servicename "MyService" -displayname "My Service" -description "This is my service."

Bir ServiceInstaller ve tüm bunları bağlamanız gerekmez - TopShelf her şeyi sizin için yapar.


1
Merhaba, bu alıyorum: - "'Topshelf 4.0.1' paketi yüklenemedi. Bu paketi '.NETFramework, Sürüm = v4.5' hedefleyen bir projeye yüklemeye çalışıyorsunuz, ancak paket herhangi bir içermiyor derleme referansları veya bu çerçeveyle uyumlu içerik dosyaları. " burada yanlış olan ne?

3
İstemci profilini değil, tam .NET 4.5.2 çalışma zamanını hedeflediğinizden emin olun.
saille

lütfen myservice.exe dosyasına daha fazla ışık atabilir ve hangi
dizinden

1
@Izuagbala myservice.exe, kod örneğinde gösterildiği gibi TopShelf önyükleme ile oluşturduğunuz konsol uygulamasıdır.
saille

Hizmet olarak yüklendikten sonra myservice.exe konsol olarak çalıştırılabilir mi? Belgeler net değil: "Konsol uygulaması oluşturulduktan sonra, geliştirici tek bir hizmet sınıfı oluşturur" docs.topshelf-project.com/en/latest/overview/…
Michael Freidgeim

28

İşte size tam bir izlenecek yol:

  1. Yeni Konsol Uygulaması projesi oluşturun (örn. MyService)
  2. İki kütüphane başvurusu ekleyin: System.ServiceProcess ve System.Configuration.Install
  3. Aşağıda yazdırılan üç dosyayı ekleyin
  4. Projeyi derleyin ve "InstallUtil.exe c: \ path \ to \ MyService.exe" komutunu çalıştırın
  5. Şimdi hizmet listesinde MyService'i görmelisiniz (run services.msc)

* InstallUtil.exe genellikle burada bulunabilir: C: \ windows \ Microsoft.NET \ Framework \ v4.0.30319 \ InstallUtil.ex‌ e

program.cs

using System;
using System.IO;
using System.ServiceProcess;

namespace MyService
{
    class Program
    {
        public const string ServiceName = "MyService";

        static void Main(string[] args)
        {
            if (Environment.UserInteractive)
            {
                // running as console app
                Start(args);

                Console.WriteLine("Press any key to stop...");
                Console.ReadKey(true);

                Stop();
            }
            else
            {
                // running as service
                using (var service = new Service())
                {
                    ServiceBase.Run(service);
                }
            }
        }

        public static void Start(string[] args)
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} started{1}", DateTime.Now, Environment.NewLine));
        }

        public static void Stop()
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} stopped{1}", DateTime.Now, Environment.NewLine));
        }
    }
}

MyService.cs

using System.ServiceProcess;

namespace MyService
{
    class Service : ServiceBase
    {
        public Service()
        {
            ServiceName = Program.ServiceName;
        }

        protected override void OnStart(string[] args)
        {
            Program.Start(args);
        }

        protected override void OnStop()
        {
            Program.Stop();
        }
    }
}

MyServiceInstaller.cs

using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace MyService
{
    [RunInstaller(true)]
    public class MyServiceInstaller : Installer
    {
        public MyServiceInstaller()
        {
            var spi = new ServiceProcessInstaller();
            var si = new ServiceInstaller();

            spi.Account = ServiceAccount.LocalSystem;
            spi.Username = null;
            spi.Password = null;

            si.DisplayName = Program.ServiceName;
            si.ServiceName = Program.ServiceName;
            si.StartType = ServiceStartMode.Automatic;

            Installers.Add(spi);
            Installers.Add(si);
        }
    }
}

1
Projenizi 64 bit için derliyorsanız, burada bulunan 64 bit için InstallUtil.exe'yi kullanmanız gerekir: C: \ windows \ Microsoft.NET \ Framework64 \ ... 32 bit sürümü (C: \ windows \ Microsoft.NET \ Framework) size bir BadImageFormatException
kuracak

Bu çok iyi çalışıyor, @snytek'in dediği gibi, 64 tabanını kullanıyorsanız, doğru dizini kullandığınızdan emin olun. Ayrıca, benimle aynı işlemi yaparsanız ve hizmeti "MyService" dışında bir adla değiştirmeyi unutursanız, kodda değişiklik yapmadan önce hizmeti kaldırdığınızdan emin olun.
dmoore1181

3

Tekrarlanan kodu durdurmak için bir derleme isteyen noktasını duyuyorum ama, en basit olurdu ve kod tekrarını azaltın ve eğer kodunuzu gelecekte başka şekillerde yeniden kullanmayı kolaylaştırırsanız ... 3 derlemeye ayırırsınız.

  1. Tüm işleri yapan tek kütüphane montajı. Sonra iki çok ince / basit projeniz var:
  2. komut satırı olan
  3. Windows hizmeti olan bir.

1
Yıllardır böyle yaptım - Servis hemen hemen var Start()ve Stop()yöntemler ve konsol uygulaması bir döngü var. TopShelf gibi bir çerçeve kullanmamadan , bu en iyi seçenektir
Temel

bu cevaba en çok katılıyorum. basit çözümler için 3d parti araçlarını kullanmak gelecekteki bakımları gereksiz hale getirir
tatigo

3

En son .Net Core 3.1 tabanlı bir Konsol Uygulamasını Çalışan Hizmet olarak Windows Hizmetine dönüştürmenin daha yeni bir yolu .

Visual Studio 2019'dan bir Çalışan Hizmeti oluşturursanız, bir Windows Hizmeti oluşturmak için ihtiyacınız olan hemen hemen her şeyi sağlar, bu da konsol hizmetini bir Windows Hizmetine dönüştürmek için değiştirmeniz gereken şeydir.

Yapmanız gereken değişiklikler şunlardır:

Aşağıdaki NuGet paketlerini kurun

Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.0
Install-Package Microsoft.Extensions.Configuration.Abstractions -Version 3.1.0

Program.cs dosyasını aşağıdaki gibi bir uygulamaya sahip olacak şekilde değiştirin:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).UseWindowsService().Build().Run();
        }

        private static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

ve servis işlemleri tarafından çalıştırılacak kodu koyacağınız Worker.cs dosyasını ekleyin:

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class Worker : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            //do some operation
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            return base.StopAsync(cancellationToken);
        }
    }
}

Her şey hazır olduğunda ve uygulama başarıyla oluşturulduğunda, aşağıdaki komutla konsol uygulama exe'nizi bir Windows Hizmeti olarak yüklemek için sc.exe'yi kullanabilirsiniz :

sc.exe create DemoService binpath= "path/to/your/file.exe"

2

Kullanabilirsiniz

reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run /v ServiceName /d "c:\path\to\service\file\exe"

Ve servis listesinde görünecektir. Bunun doğru çalışıp çalışmadığını bilmiyorum. Bir servis genellikle birkaç olayı dinlemek zorundadır.

Gerçi, herhangi bir uygulamayı gerçek bir hizmet olarak çalıştırabilen birkaç hizmet sarıcısı vardır. Örnek Microsoftun için SrvAny dan Win2003 Resource Kit


Dediğiniz gibi, hizmet exe windows ile iletişim kurmak gerekir. SrvAny
Jodrell

5
Bu yaklaşımı güvensiz buluyorum. Windows, hizmetleri yönetmek için özel kitaplıklara ve yardımcı programlara sahiptir ve farklı işletim sistemi sürümlerinde ve ortamlarında tutarlı olarak çalışma olasılıkları daha yüksektir. .NET uygulaması için VS'de bir MSI yükleyicisi oluşturmak oldukça kolaydır. Kurulumu ManagedInstallerClass.InstallHelper yöntemini kullanarak programlı olarak gerçekleştirmek de mümkündür.
VladV

1
Yükleyicilere ve diğer şeylere gerek yok: sadece bu komut satırını kullanın: sc create MyServiceName binPath = "c: \ path \ to \ service \ file \ exe"
JDC

2

Öncelikle konsol uygulama çözümünü windows servis çözümüne gömdüm ve referans verdim.

Sonra konsol uygulaması Program sınıfını herkese açık hale getiriyorum

/// <summary>
/// Hybrid service/console application
/// </summary>
public class Program
{
}

Sonra konsol uygulamasında iki işlev oluşturuyorum

    /// <summary>
    /// Used to start as a service
    /// </summary>
    public void Start()
    {
        Main();
    }

    /// <summary>
    /// Used to stop the service
    /// </summary>
    public void Stop()
    {
       if (Application.MessageLoop)
            Application.Exit();   //windows app
        else
            Environment.Exit(1);  //console app
    }

Daha sonra windows hizmetinin içinde, Programı başlatır ve OnStart ve OnStop içine eklenen Start ve Stop işlevlerini çağırırım. Aşağıya bakınız

class WinService : ServiceBase
{
    readonly Program _application = new Program();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] servicesToRun = { new WinService() };
        Run(servicesToRun);
    }

    /// <summary>
    /// Set things in motion so your service can do its work.
    /// </summary>
    protected override void OnStart(string[] args)
    {
        Thread thread = new Thread(() => _application.Start());
        thread.Start();
    }

    /// <summary>
    /// Stop this service.
    /// </summary>
    protected override void OnStop()
    {
        Thread thread = new Thread(() => _application.Stop());
        thread.Start();
    }
}

Bu yaklaşım, bir windows uygulaması / windows hizmeti hibriti için de kullanılabilir


Bu temelde JonAlb'nin önceki cevapta söylediği şey, ancak kod örneği için teşekkürler
tatigo

0

Belki de ihtiyacınız olanı tanımlamalısınız, bildiğim kadarıyla, uygulamanızı aynı anda komut satırı ile Konsol veya Hizmet olarak çalıştıramazsınız. Hizmetin yüklü olduğunu ve Hizmet Yöneticisi'nde başlatmanız gerektiğini unutmayın; hizmeti başlatan veya konsol uygulamanızı çalıştıran yeni bir işlem başlatan yeni bir uygulama oluşturabilirsiniz. Ama yazdığın gibi

"konsol uygulamasını tek bir proje olarak sakla"

Bir keresinde, bir konsol uygulamasını bir hizmete dönüştürerek pozisyonunuzdaydım. Öncelikle VS Express Edition ile çalışıyorsanız şablona ihtiyacınız var. İşte ilk adımlarınızı atabileceğiniz bir bağlantı: C # Windows Service , bu benim için çok yardımcı oldu. Ardından bu şablonu kullanarak, kodunuzu hizmetin istenen olaylarına ekleyin.

Hizmetinizi geliştirmek için yapabileceğiniz başka bir şey var, ancak bu hızlı ve / veya kolay değil, etki alanlarını kullanıyor ve yüklemek / boşaltmak için dll'ler oluşturuyor. Birinde konsol uygulaması ile yeni bir işlem başlatabilirsiniz ve başka bir dll sadece hizmet yapmak zorunda işlevselliği koyabilirsiniz.

İyi şanslar.


0

İşlevi bir sınıfa veya sınıflara ayırmanız ve bunu iki taslaktan biri aracılığıyla başlatmanız gerekir. Konsol saplaması veya servis saplaması.

Açıkça görüldüğü gibi, pencereleri çalıştırırken, altyapıyı oluşturan sayısız hizmetler konsol pencerelerini kullanıcıya sunmaz (ve doğrudan yapamaz). Hizmetin kullanıcıyla grafik olmayan bir şekilde iletişim kurması gerekir: SCM üzerinden; Olay günlüğünde, bazı günlük dosyalarına vb. Hizmetin ayrıca SCM aracılığıyla pencerelerle iletişim kurması gerekir, aksi takdirde kapanır.

Hizmetle iletişim kurabilen bazı konsol uygulamalarına sahip olmak açıktır, ancak hizmetin GUI etkileşimi için bir gereksinim olmadan bağımsız olarak çalışması gerekir.

Konsol saplaması, hizmet davranışının hatalarını ayıklamak için çok yararlı olabilir, ancak sonuçta bir hizmet yaratma amacı olan "üretim" ortamında kullanılmamalıdır.

Tam olarak okumadım ama bu makale doğru yönde pint gibi görünüyor.


0

Ben reçete standart standart takip bir servis sınıfı kullanın ServiceBaseve kolay F5 hata ayıklama yardımcı olur. Bu, servis içinde tanımlanan servis verilerini tutar, bulunmasını ve kullanım ömürlerinin yönetilmesini kolaylaştırır.

Normalde aşağıdaki yapıya sahip bir Windows uygulaması oluştururum. Bir konsol uygulaması oluşturmuyorum; Bu şekilde, uygulamayı her çalıştırdığımda yüzümde büyük bir kara kutu patlamıyorum. Tüm eylemin olduğu yerde hata ayıklayıcıda kalıyorum. Kullandığım Debug.WriteLinemesajlar çıktı penceresine gidin böylece hangi rıhtım güzel ve uygulama sona erdiği sonra görünür kalır.

Genellikle durdurmak için hata ayıklama kodu eklemek zahmet etmeyin; Bunun yerine hata ayıklayıcıyı kullanıyorum. Durdurma hata ayıklaması gerekiyorsa, projeyi bir konsol uygulaması yapmak, Stopiletici yöntemi eklemek ve bir çağrıdan sonra çağırmak Console.ReadKey.

public class Service : ServiceBase
{
    protected override void OnStart(string[] args)
    {
        // Start logic here.
    }

    protected override void OnStop()
    {
        // Stop logic here.
    }

    static void Main(string[] args)
    {
        using (var service = new Service()) {
            if (Environment.UserInteractive) {
                service.Start();
                Thread.Sleep(Timeout.Infinite);
            } else
                Run(service);
        }
    }
    public void Start() => OnStart(null);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.