Страницы

суббота, 8 июня 2013 г.

Создание Windows Service Application с ипользование Topshelf

Всем хорошо известно, как создавать Windows Service Application, если нет, то смотрим MSDN. Но отлаживать его функциональность жутко неудобно, да иногда сервис и не нужен, а хочется запустить приложение в консольном виде. Для реализации такой задачи существует замечательный продукт Topshelf.

И так, если кратко, то Topshelf позволяет вести разработку Windows Service Application в виде консольного приложения, а так же позволяет использовать приложение как в виде Console Application, так и в виде Windows Service Application. Далее посмотрим на наиболее вероятные сценарии использования Topshelf.
Для экспериментов будем реализовывать простейший сервис, который раз в две секунды будет производить запись информации в файл. Формат записи: <counter value> - <время записи>
Кадждый из проверяемых сценариев будет представлять отдельный проект в solution TopshelfTest  и реализацию делаем под Visual Studio 2012 .Net 4.0. Все действия производятся с актуальной версией Topshelf, на текущий момент, а именно 3.1.1 от 24.03.2013.

Подготовка
Создаем пустой Visual Studio Solution TopshelfTest. Здесь мы будем создавать все проекты для разных сценариев использования Topshelf

Простейший сервис (SimpleService)
Создание
1. Создаем новый проект, типа Console Application, SimpleService
2. Используя NuGet Packet Manager подключаем Topshelf
3. Создаем класс реализующий логику создаваемого сервиса, наследуясь от Topshelf.ServiceControl
При запуске сервиса исполняется метод Start являющийся abstract методом ServiceControl в данном методе мы начинаем основную нить работы нашего сервиса, при запросе на остановку сервиса срабатываем метод Stop, в котором мы останавливаем основную нить и завершаем работу. Методы Start и Stop возвращают boolean в которой передается информация о успешности выполнения операции.
4. Встраиваем запуск созданного класса сервиса в main используя Topshelf.HostFactory
Вот в принципе и все, у нас все готово, обращаю внимание, что в процессе разработки мы совершенно спокойно запускаем приложение в режиме отладки, как обычное Console Application.

Использование Console Application
Идем в каталог bin и запускаем исполняемый файл приложения:
Приложение запущено, для остановки Topshelf сервиса, в режиме console application используется сочетание Ctrl + C
В результате работы видим созданный файл SimpleServiceOutput.txt
Использование Windows Service Application
Теперь попробуем использовать созданное приложение в качестве Windows Service Application,

Установка сервиса
Переходим в командную строку и производим установку созданного приложения в качестве Windows service, используя команды install (Внимание: command prompt должен быть запущен с правами администратора системы)
Проверяем, что приложение появилось в списке сервисов системы

Запуск и остановка сервиса
Тут возможны два варианта:
1. Командная строка
Запуск производится с использованием команды start
Остановка с использование команды stop, остановку производим через несколько секунд, чтобы увидеть результаты работы
В результатах работы, мы видим, что сервис корректно стартовал и остановился
2. Стандартный интерфейса системы
Ну тут все просто, мы используем стандартные возможности, предоставляемые системой.
Запуск

Остановка

Результаты работы

Деинсталляция сервиса
Деинсталляция сервиса из системы производится из коммандной строки

Сервис со специализированным конструктором
Иногда есть необходимость использовать специфичный конструктор класса сервиса, т.е. не использовать конструктор по умолчанию.
Например, для нашего сервиса нам нужно передавать стартовое значение счетчика.
Для проверки данной функциональности создадим еще один проект Console application ServiceWithSpecificConstructor.
Класс сервиса очень похож на класс SimpleService, за исключение того, что начальное значение counter устанавливается из конструктора
В Program.cs изменим запуск нашего сервиса, создавая класс ServiceWithSpecificConstructor с определенным параметром, а именно наш счетчик будет стартовать со значения 1000
В данном случае используем прямое создание объекта класса, но никто не мешает нам для создания объекта использовать специализированную фабрику.

Проверку работы делаем через консольное приложение, т.к. теорема существования Windows Service Application уже доказана.
Настройки host процесса
Как мы видели на примере SimpleService в режиме Windows Service Application, установленный сервис имеет режим запуска Automatic, запускается как Local Service и имеет имя равное имени класса реализующего логику сервиса (т.е. SimpleService).
Это не очень информативно, поэтому посмотрим что нам может предложить Topshelf
Topshelf имеет два пути решения данной задачи:
  1. Установка параметров через командную строку.
  2. Установка параметров через код.
Попробует настроить Windows Service Application с следующим параметрами
Name: TestServiceName
Description: TestService description
Start mode: Manual
Log on: Network service

Параметры через командную строку
Для работы через командную строку вернемся к SimpleService и установим его через командную строку, используя дополнительные параметры:
В результате мы видим установленный SimpeService, но имеющий совершенно другие настройки
Общий список сервисов
Основные свойства сервиса
Log on свойства

Обращаю внимание, что команда unistall без дополнительных параметров уже не срабатывает, т.к. сервис зарегистрирован с системе под другим именем. Для выполнения uninstall необходимо указать имя сервиса:
Параметры через код
Командная строка хорошо, но большинство параметров хотелось бы устанавливать по умолчанию. И такая возможность так же предоставляется Topshelf. Для проверки созданим новый проект SimpleServiceWithHostProperties. Проект полность совпадает с проектом SimpleService, за исключением main, т.к. именно там мы задаем свойства host процесса.
Установим сервис из командной строки
Вставлять картинки не буду, но результат аналогичен действиям через командную строку.
Команда uninstall теперь работает без каких-либо дополнительных параметров Использование настроек host процесса в сервисе
Создание
Вполне нормальный вариант сценария, когда нам необходимо запустить несколько экземпляров сервиса. Для этого необходимо указать имя экземпляра при установке сервиса.
Создадим новый проект SimpleServiceInstance, аналогичный SimpleService, но изменив его поведение: имя формируемого файла будет: "SimpleService_<instance name>.txt". Для того что бы получить доступ к имени экземпляра в классе сервиса, в конструктор мы должны получить свойства host процесса.
Теперь запуск сервиса в main выглядит следующим способом

Установка
Теперь, из командой строки установим два экземпляра сервиса, с именами экземпляров 01 и 02
В списке сервисов видим наши установленные экземпляры

Запуск
Запуск возможен, как через стандартный интерфейс системы, так и через командную строку
В результате работы, в каталоге у нас появились два файла SimpleService_01.txt и SimpleService_02.txt, этот тот результат которого и добивались.

Выводы
Topshelf полезный и гибкий продукт, позволяющий упростить и ускорить разработку и откладку Windows Service Application, а так же упростить развертывание проекта в производственной среде. В рамках данного поста описана только часть возможностей Topshelf, для получения более подробной информации смотрите документацию на сайте проекта.
Вот краткий список того, что даже не затрагивалось:
  • Описание зависимостей от других сервисов
  • Поддержка Pause/Resume/Reset/Shutdown
  • Интеграция с системами логирования Log4Net и NLog
  • Выполнение дополнительных действий при установке и удалении сервиса
  • Конфигурирование режима Recovery


Solution для VisualStudio 2012, со всеми проектами из данного поста, можно взять тут.

5 комментариев :

  1. а будут ли статьи про

    Описание зависимостей от других сервисов
    Поддержка Pause/Resume/Reset/Shutdown
    Интеграция с системами логирования Log4Net и NLog
    Выполнение дополнительных действий при установке и удалении сервиса
    Конфигурирование режима Recovery

    ОтветитьУдалить
    Ответы
    1. Для интеграции есть пакет nuget Topshelf.NLog

      Пока остальное не планировал описывать

      Удалить
  2. в первом же примере. Ошибка "TopShelf.SimpleService.Dispose(bool)": не найден метод, пригодный для переопределения 14 33

    ОтветитьУдалить
  3. можно ли указать от чьего имени запускать сервис?

    ОтветитьУдалить