Консольное приложение .NET как служба Windows - PullRequest
130 голосов
/ 14 октября 2011

У меня есть консольное приложение, и я хотел бы запустить его как службу Windows.VS2010 имеет шаблон проекта, который позволяет прикрепить консольный проект и построить сервис Windows.Я не хотел бы добавлять отдельный сервисный проект и, если возможно, интегрировать сервисный код в консольное приложение, чтобы консольное приложение оставалось одним проектом, который мог бы работать как консольное приложение или как служба Windows, если он запускается, например, из командной строки с помощью переключателей.

Может быть, кто-то может предложить библиотеку классов или фрагмент кода, который может быстро и легко преобразовать консольное приложение c # в службу?

Ответы [ 9 ]

168 голосов
/ 14 октября 2011

Я обычно использую следующую технику для запуска того же приложения, что и консольное приложение или как служба:

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.UserInteractive обычно имеет значение true для консольного приложения и false для службы.Технически, можно запустить службу в интерактивном режиме, поэтому вместо этого вы можете проверить переключатель командной строки.

48 голосов
/ 04 августа 2014

Я имел большой успех с TopShelf .

TopShelf - это пакет Nuget, разработанный для упрощения создания приложений .NET Windows, которые могут работать как консольные приложения или как службы Windows. Вы можете быстро подключить события, такие как события запуска и остановки вашего сервиса, настроить с помощью кода, например, чтобы настроить учетную запись, с которой он работает, настроить зависимости от других служб и настроить способ восстановления после ошибок.

Из консоли диспетчера пакетов (Nuget):

Install-Package Topshelf

Обратитесь к образцам кода , чтобы начать.

Пример:

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 также заботится об установке службы, которая может сэкономить много времени и удаляет стандартный код из вашего решения. Чтобы установить .exe в качестве службы, просто выполните следующее из командной строки:

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

Вам не нужно подключать ServiceInstaller и все такое - TopShelf сделает все за вас.

23 голосов
/ 21 января 2017

Итак, вот полное пошаговое руководство:

  1. Создание нового проекта консольного приложения (например, MyService)
  2. Добавление двух ссылок на библиотеки: System.ServiceProcess и System.Configuration.Install
  3. Добавьте три файла, напечатанные ниже
  4. Создайте проект и запустите «InstallUtil.exe c: \ path \ to \ MyService.exe»
  5. Теперь вы должны увидеть MyService в списке служб(запустите services.msc)

* InstallUtil.exe обычно можно найти здесь: 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);
        }
    }
}
2 голосов
/ 13 февраля 2015

Сначала я встраиваю консольное приложение в решение службы Windows и ссылаюсь на него.

Затем я делаю консольное приложение Класс программы общедоступным

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

Затем я создаю две функции в консольном приложении

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

Затем в самой службе Windows я создаю экземпляр Программы и вызываю функции Start и Stop, добавленные в OnStart и OnStop. Смотри ниже

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

Этот подход также можно использовать для гибридного приложения Windows / службы Windows

2 голосов
/ 14 октября 2011

Я слышал, что вы хотели, чтобы одна сборка остановила повторяющийся код, но было бы проще и сократить повторение кода, а также упростить повторное использование вашего кода в будущем, если ...... если вы взломаете его на 3 сборки.

  1. Одна сборка библиотеки, которая делает всю работу. Тогда есть два очень очень тонких / простых проекта:
  2. тот, который является командной строкой
  3. тот, который является службой Windows.
2 голосов
/ 14 октября 2011

Вы можете использовать

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

И оно появится в списке услуг. Я не знаю, правильно ли это работает, хотя. Служба обычно должна прослушивать несколько событий.

Есть несколько сервисных оболочек, которые могут запускать любое приложение как реальный сервис. Например, Microsoft SrvAny из Win2003 Resource Kit

0 голосов
/ 12 марта 2019

Я использую класс обслуживания, который следует стандартному шаблону, предписанному ServiceBase, и использую помощники для легкой отладки F5. Благодаря этому данные сервиса определяются в сервисе, что облегчает их поиск и управление жизненным циклом.

Обычно я создаю приложение для Windows со структурой ниже. Я не создаю консольное приложение; таким образом, я не получаю большой черный ящик каждый раз, когда я запускаю приложение. Я остаюсь в отладчике, где все действия. Я использую Debug.WriteLine, чтобы сообщения отправлялись в окно вывода, которое хорошо стыкуется и остается видимым после завершения работы приложения.

Я обычно не пытаюсь добавить отладочный код для остановки; Я просто использую отладчик вместо этого. Если мне нужно отладить остановку, я делаю проект консольным приложением, добавляю метод Stop forwarder и вызываю его после вызова 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);
}
0 голосов
/ 14 октября 2011

Вам нужно разделить функциональность на класс или классы и запустить их через одну из двух заглушек.Заглушка консоли или заглушка службы.

Как видно, при запуске окон множество сервисов, составляющих инфраструктуру, не (и не могут напрямую) представлять окна консоли пользователю.Служба должна общаться с пользователем не графическим способом: через SCM;в журнале событий, в некоторый файл журнала и т. д. Служба также должна будет взаимодействовать с окнами через SCM, в противном случае она отключится.

Очевидно, что было бы приемлемо иметь какое-то консольное приложение, которое может взаимодействовать сслужба, но служба должна работать независимо без необходимости взаимодействия с графическим интерфейсом.

Заглушка консоли может быть очень полезна для отладки поведения службы, но ее не следует использовать в «производственной» среде, которая, в конце концов, являетсяЦель создания сервиса.

Я не прочитал его полностью, но эта статья , кажется, показывает в правильном направлении.

0 голосов
/ 14 октября 2011

Может быть, вам следует определить, что вам нужно, насколько я знаю, вы не можете одновременно запускать приложение как консоль или службу с командной строкой. Помните, что служба установлена, и вы должны запустить ее в диспетчере служб, вы можете создать новое приложение, которое запустит службу или запустит новый процесс, выполняющий ваше консольное приложение. Но, как вы написали

"сохранить консольное приложение как один проект"

Однажды я оказался на вашем месте, превращая консольное приложение в сервис. Сначала вам нужен шаблон, если вы работаете с VS Express Edition. Вот ссылка, где вы можете сделать свои первые шаги: C # Windows Service , это было очень полезно для меня. Затем, используя этот шаблон, добавьте свой код к нужным событиям сервиса.

Чтобы улучшить свой сервис, есть еще одна вещь, которую вы можете сделать, но это не быстро и / или легко, это использование доменов приложений и создание библиотек DLL для загрузки / выгрузки. В одном вы можете запустить новый процесс с помощью консольного приложения, а в другом dll вы можете просто добавить функциональность, которую должен выполнять сервис.

Удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...