Пишем свой Windows service

    Многие из нас сталкиваются с такой задачей, когда нужно запускать своё приложение при запуске компьютера. Конечно можно поместить ярлык в автозагрузку, но как-то это неправильно. Да к тому же если комп перегрузился, а пользователь не залогинелся, то и ваше приложение тоже не запустится.

    Самым верным решением в данной ситуации является написание Windows сервиса.

    Пример создания сервиса в Studio 2010, .Net C# под катом

    Шаг 1. Создание проекта.



    Создайте новый проект, выбрав шаблон Windows Service



    Переименуйте класс сервиса как вам нужно.



    Получили такой вод код:

    namespace ExampleSrv
    {
      public partial class MyService : ServiceBase
      {
        public MyService()
        {
          InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
      }
    }


    * This source code was highlighted with Source Code Highlighter.


    Это и есть, собственно, сам сервис.
    Используйте OnStart и OnStop события для реализации своей поставленной задачи.

    Шаг 2. Добавление установщика.


    Чтобы ваш сервис заставить работать, его нужно установить.
    Чтобы его установить, он должен иметь установщик.

    Клик правой кнопкой… Add installer



    Теперь у нас есть serviceProcessInstaller и serviceInstaller

    img04

    В первом можете поставить значение Account в LocalSystem.
    Во втором укажите имя сервиса, описание и не забудьте поставить StartTypeAutomatic.



    Установщик готов.

    Шаг 3. Логирование.


    Для того чтобы вы смогли узнать что делал ваш сервис, когда он стартовал, завершался или что-нибудь еще, вы можете использовать системное логирование.
    Делается это очень легко.
    Перетаскиваете из Toolbox в свой сервис EventLog.



    Примерно так делается логирование:

    public partial class MyService : ServiceBase
      {
        public MyService()
        {
          InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
          AddLog("start");
        }

        protected override void OnStop()
        {
          AddLog("stop");
        }

        public void AddLog(string log)
        {
          try
          {
            if (!EventLog.SourceExists("MyExampleService"))
            {
              EventLog.CreateEventSource("MyExampleService", "MyExampleService");
            }
            eventLog1.Source = "MyExampleService";
            eventLog1.WriteEntry(log);
          }
          catch{}
        }
      }


    * This source code was highlighted with Source Code Highlighter.


    Шаг 4. Установка.


    Чтобы установить сервис, нужно вызвать утилиту установки и передать параметром путь к своему сервису.
    Для этого я создал install.bat такого вида:

    C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe D:\...\ExampleSrv\bin\Debug\ExampleSrv.exe
    pause


    Если вы выбрали в serviceProcessInstaller значением поля AccountUser, то при установке вы должны будете ввести логин и пароль учетной записи, под которой будет запускаться сервис. Внимание! Писать домен перед именем пользователя обязательно!

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

    The Commit phase completed successfully.
    The transacted install has completed.


    Это значит что сервис установлен.
    Проверяем:



    Установился.


    Пару раз делаем запуск и остановку. Смотрим логи:



    Видим когда сервис запускался и останавливался.


    Наш сервис готов.


    Материал частично взят от сюда:
    msdn.microsoft.com/en-us/library/zt39148a(VS.80).aspx
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 47
    • +1
      Пустой проект создать не сложно…
      Убивают нюансы)
      Например, удаление сервиса всё также через одно место, если открыто окно сервисов — получите ошибку.
      Отладка это наше всё… Если есть ошибка в процедуре(не синтаксическая, конечно, например, неверный ип для коннекта), то без поллитры не разберёшся, вызвалась ли эта процедура вообще(разумеется, возмоности чуть более вменяемой отладки требуют покупки Ultimate лицензии). И прочее, прочее…
      • +15
        Для «вменяемой отладки» достаточно писать вменяемые логи и расставлять вменяемые ассерты.

        О, поколение, испорченное дебаггерами…
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            То есть точки остановки как бы не нужны?
            • +4
              Вообще интерактивный дебаг как бы не нужен. Точнее, он очень нужен для посмертного вскрытия корок, и для отладки чужого и очень плохого кода.

              А свой код можно и нужно изначально писать так, чтобы пользоваться правильными техниками отладки. Без всяких там break points и прочего.
          • 0
            Коммент, достойный уважения)
            На моей памяти(могу и раскопать тот специфический проектик на C#), даже запись лога в том варианте просто кричала о том, что процедура не была вызвана.

            Тоесть, функция вида
            {
            запись в лог 1;

            строка с ошибкой в создании объекта;

            запись в лог 2;
            return ...;
            }

            Не делала записей в лог-файл вообще. Attach-to-proccess также показывал пропуск этой процедуры. При исключении же строки с ошибкой процедура выполнялась.
            Отладили как раз созданием консольного приложения, где эта процедура всё-таки вызывалась, хоть и с ошибкой.
            • +1
              А вы лог флашили?

              Вообще, первое правило — писать вывод логов и ассерты сразу и везде. Это, кроме всего прочего, еще и дополнительные аннотации к коду, проще читать потом будет. Нельзя проверки просто навешать потом на код вокруг подозрительного места — ведь реально ошибка может быть где-то еще, далеко от того, где все сломалось.
              • 0
                Что более забавно, изначально, лог флашился только на событиях опаснее некоторого уровня и при остановке сервиса, впрочем, исправление не привело прямиком к успеху.
                После работы посмотрю, что там конкретно было, но повторюсь — функция, согласно дебаггеру, вообще не вызывалась.
                Кстати, «опасный» код был в блоке try, у которого в catch также была запись в лог, что добавило к ловле блох как минимум час.
                • 0
                  Все эти симптомы говорят, что реальная ошибка где-то вовсе за пределами этого блока кода. Довольно редкий случай в .NET, правда, если unmanaged-вызовами особо не баловаться.
                  • 0
                    Эта строка создавала подключение к SIMATIC OPC Server.
                    Соседнее же присоединение к PostgreSQL при неверных параметрах выдавало вполне вменяемое исключение.

                    Мой опыт в .NET довольно скромен, потому склонен довериться Вашему мнению.

                    Всё же, убивали в сервисах именно нюансы, и с первой попытки запустить что-либо сложнее приведённого примера может выйти не у каждого.
            • 0
              Более того, для вменяемой отладки нужно несколько способов запуска приложения: один — запуск в виде сервиса, двугой — в виде стандартного консольного приложения, в котором вся отладка прекрасно работает. Запустил приложение без ключа — стандартное консольное приложение, запустил с ключом /service — сервис.
              • 0
                Есть и вариант наоборот (для .NET и Java и вообще любой рефлексивной среды работает идеально) — встроить в приложение консоль для отладки. REPL какого либо скриптового языка, к которому можно подцепиться telnet-ом, и не прерывая работы выполнить произвольный код в контексте приложения.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +3
              По собственному опыту — легче сначала разрабатывать в виде консольного приложения, затем оформлять его в виде сервиса.
              • 0
                А что, разве нельзя сделать «Attach to process»? Там ведь не так сложно было. Я правда сервисы не писал давно (около двух лет), поэтому могу не помнить подробностей. Просто запускаешь службу, делаешь «Attach to process», выбираешь показывать все процессы, выбираешь нужный и можно дебажить пошагово. VS была, если не ошибаюсь, 2008 Prof, но думаю такая возможность и в express есть (не могу проверить).
                • +1
                  Можно, это работает. Проблема в том что так вы не сможете отдебажить стартап код.
                  • 0
                    Ну я в свое время (давно уже) писал такое: bitbucket.org/jonie/winsrvdebughelper
                    Просто давите F5 в проекте и получаете окно управления проектными сервисами (их может быть не один в рамках одного проекта)… конечно, надо учитывать права из под кого будет запускаться сервис в дебаге и в реальности (как раз в примере по ссылке производится запись в корень C:\ что даст сбой при ограниченном аккаунте).

                    ЗЫ: у автора может быть проблемы с вылетанием при записи логов при сильно ограниченном аккаунте под кем стартует сервис…
                    • 0
                      нет, не будет вылетаний, там же try
                    • 0
                      Не знаком с тонкостями .Net приложений, но в плюсах просто декларировал время старта сервиса порядка 15 секунд и при старте Sleep секунд на 10, за это время вполне успеваешь приаттачить отладчик.
                      Извращение конечно, но ошибку поймать удалось (не правильно прописал одно из полей).
                  • +1
                  • +3
                    Слишком «для школьников»
                    • +3
                      так а зачем всё усложнять если оно так и есть ;)
                    • +1
                      Для отладки я использую такую схему:
                      Всю логику сосредотачиваю в dll, которую подключаю к сервису.
                      Плюс к этому я создаю обычный винформс аппликейшн, к которому тоже подрубаю эту dll.
                      Вот тут разворачивается простор для дебага.

                      А описанный мною в статье шаблон сервиса отлично подходит как раз для подключения и использования какой-нить библиотеки.
                      • 0
                        Вообщето для отладки достаточно скомпилировать проект. Инсталировать сервис, и при запуске сервиса в течении 30 секунд присоединится к процессу сервиса, ну и ставить бряки в сырцах сервиса. Вуаля, дебаг аналогичный как и дебаг простого приложения.
                        • 0
                          А если нужно дебажить прямо со старта сервиса, и не хочется вставлять таймауты, что бы успеть приаттачится, то можно первой коммандой сделать.

                          Debugger.Launch();
                          • 0
                            Это тоже работает. А можно как делает 99% человечества, а именно в конскольке запускать.
                          • 0
                            И кстати, метод OnStart в сервисе должен отработать за указанные 30 секунд, иначе получим ошибку запуска сервиса.
                        • +5
                          У меня тоже есть пост на тему написания сервисов. В посте показан поллинг-сервис с саморегистрацией и запуском из консоли — эти две фичи у меня фигурируют во всех сервисах.

                          Вообщем, имхо, хабру нужны более техничные статьи — тема-то большая.
                          • +1
                            Поддерживаю, все сервисы пишу с саморегистрацией и возможность работы просто из командной строки — запустить без инсталяции и чтобы так же выполнял свои задачи. Во время разработки очень удобная штука, не нужно устанавливать сервис, а просто отлаживаешь как обычное консольное приложение.
                            • +2
                              Для этого даж проект специальный есть github.com/topshelf/topshelf
                            • 0
                              проще воспользоваться прогами вроде AppToService, которые любой приложение умеют запускать как службу.
                              • +2
                                вот способ от microsoft по запуску любого приложения как службы: www.py-my.ru/post/4bfb3c691d41c846bc000044
                                • 0
                                  тогда тем более не понятно о чём топик. Переизобретение велосипеда?
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                • +1
                                  «Многие из нас сталкиваются с такой задачей, когда нужно запускать своё приложение при запуске компьютера. Конечно можно поместить ярлык в автозагрузку, но как-то это неправильно. Да к тому же если комп перегрузился, а пользователь не залогинелся, то и ваше приложение тоже не запустится. „

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

                                  В частности, сервис надо писать так, чтобы он умел работать в Non-interactive (без окон, консоли, без всего), и умел корректно закрываться по соответствующим командам системы. Приложению на это начхать.
                                • +3
                                  Переписанная статься из мсдн с кучей ошибок, что может быть более достойно главной?
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                    • 0
                                      Я вообще давно написал вот такой универсальный скелетон для службы, который можно положить в common.dll и использовать во всех своих проектах, там же и пример использования, не претендую на оригинальность, код вбирает в себя все что было в туториалах, плюс то что понадобилось для себя
                                      pastebin.com/yje1MzWA
                                      • 0
                                        Там кстати добавлена возможность указания имени службы при установке через Installutil, использовать можно так:
                                        installutil /serviceName=CompanyName.Service serviceApp.exe
                                        забыл написать, пришлось ждать 5 минут )
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • 0
                                          А кто-нибудь может рассказать, как запустить, например, .torrent файл из сервиса? Process.Start, ShellExecute, CreateProcess( с указанием явного рабочего стола) не увенчались успехом. Галочка «Взаимодействие с рабочим столом» стоит. Торрент запускается, но за пределами графической оболочки винды. Есть у кого какие соображения по-этому поводу?
                                          • 0
                                            Агент нужен в том же контексте, что и торрент-софтина

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.