Страницы

воскресенье, 29 июля 2012 г.

Положи Windows Service на полку.

  Кому приходилось писать сервисы windows следуя заветам Microsoft осознаёт тяжесть (“корпоративность”) подхода. Долго, муторно, неудобно для тестирования, для отладки требуется ultimate версия студии. Возникает ощущение бега с препятствиями. Видимо схожие мысли посетили и авторов Mass Transit и Fubu Project. Они уже решили проблему создания сервисов, убрав все препятствия с трассы. Спешите освоить -  Topshelf.  

  Раздел документации на сайте не блещет полнотой, что поначалу несколько расстраивает. Хорошая новость: ее достаточно. Topshelf может работать в двух режимах:

  • installing - создание полноценной службы windows.
  • shelving – хостинг сервисов в отдельном домене приложения.

 

Installing

  Этот режим используется для создания полноценной службы windows, которой можно управлять через Service Manager. Идеологически Topshelf выполняет две операции:

  • Берёт на себя сложности связанные инфраструктурными проблемами хостинга windows-сервиса.
  • Хостинг бизнес-сервиса, выполняющего работу самого сервиса.

Эти две функции нам и надо прописать в коде:

static class Program
{
    static void Main()
    {
        HostFactory.Run(x =>
        {
            //Настройка windows-сервиса. 
            x.UseNLog();
            x.BeforeStartingServices(() => Console.WriteLine("[FooHost] Preparing to start host services"));
            x.AfterStartingServices(() => Console.WriteLine("[FooHost] All services have been started"));
            x.AfterStoppingServices(() => Console.WriteLine("[FooHost] All services have been stopped"));
            x.SetServiceName("FooHost");
            x.SetDisplayName("FooHost");
            x.SetDescription("FooHost ");
            //Сейчас запускаем как Local System, но можно запустить под любым пользователем. 
            x.RunAsLocalSystem();
            x.EnableDashboard();
            //Настройка нашего бизнес-сервиса.  
            x.Service<BarService>(y =>
            {
                y.SetServiceName("FooService");
                y.ConstructUsing(() => new FooService());
                y.WhenStarted(foo => foo.Start());
                y.WhenStopped(foo => foo.Stop());
            });
        });
        Logger.Shutdown();
    }
}

Не буду подробно останавливаться на коде, он говорит сам за себя. Добавлю: Topshelf поддерживает работу с двумя наиболее популярными логгерами – log4net и NLog2. Расширенное описание командной строки есть в исходнихах.


Преимущество режима  по сравнению с обычным сервисом:



  • Нет нужды наследовать и вручную писать ServiceInstaller и ServiceBase, что повышает тестопригодность.
  • Возможность запускать сервис в режиме консоли “из коробки”, что облегчает его отладку.
  • Внятное (даже без документации) API.

Создание нового windows-сервиса легко, но есть лучший способ хостить сервисы:


Shelving


В большинстве случаев нам не нужен полноценный windows-сервис, но мы вынуждены его писать, чтобы удовлетворить требования Windows. Отсюда вытекает логичная мысль: сделать инфраструктурный windows-сервис, который бы мог хостить бизнес-сервисы. Эту идею и реализует Topshelf.


Для начала нам понадобиться Topshelf.Host.exe. Его нет в nuget, но можно найти в исходниках проекта (я использую несколько модифицированную версию). Topshelf.Host.exe является таким же windows-сервисом, как и описанный в предыдущем разделе, и следовательно его можно запускать и как сервис, и как консоль. После запуска сервис автоматически создать подпапку Services. Topshelf мониторит эту папку, и при обнаружении изменений по необходимости подгружает


  Для дальнейшей работы необходимо реализовать Bootstrapper для своего сервиса, и сконфигурировать параметры запуска. У меня это выглядит так:

public class MazayBootstrapper : Bootstrapper<MazayService>
{
    public void InitializeHostedService(IServiceConfigurator<MazayService> cfg)
    {
        cfg.SetServiceName("Mazay");
        cfg.Named("Mazay");
        cfg.HowToBuildService(x => new MazayService(SectionHandler.Instance.Folders));
        cfg.SetServiceName("Mazay");
        cfg.WhenStarted(x => x.Start());
        cfg.WhenStopped(x => x.Stop());
    }
}

  После этого надо создать подпапку с названием сервиса в папке Service\FooService, и скопировать в нее наш сервис. Согласно описанию, сервис должен был заработать. Но заработал  только после продолжительных мытарств. Что еще раз напомнило мне о древней мудрости:  если ничего не помогает – прочитайте наконец документацию. Если и это не помогает – внимательно прочитайте документацию Улыбка Дело оказалось в двух проблемах:




  1. Добавить конфигурационный файл сервиса. Внимание: название файла должно соответствовать шаблону ‘имя_папки_сервиса.dll’, в которую мы положили сервис. Для моего случая это FooService.config, а не FooService.dll.config. Topshelf запускает сервис в отдельном домене приложения, и принудительно назначает ему этот конфигурационный файл.


  2. В конфигурационном файле необходимо указать ссылку на Bootstrapper сервиса:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section
      name="ShelfConfiguration"
      type="Topshelf.Shelving.ShelfConfiguration, TopShelf" />
  </configSections>
 
 <ShelfConfiguration
    Bootstrapper="Mazay.MazayBootstrapper, Mazay" />
</configuration>

После этого сервис заработал в штатном режиме.


Dashboard


Маленький бонус от создателей. Topshelf содержит небольшой проект Dashboard, который позволяет из браузера посмотреть, и управлять рабой сервисов. Для его подключения понадобиться nuget пакет Topshelf.DashBoard, и вписать строчку и вызвать метода расширения x.EnableDashboad() при конфигурации сервиса. Dashboard не поддаётся конфигурации, и найти его можно по адресу http://localhost:8483/TopShelf/Topshelf.Host


image


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

среда, 18 июля 2012 г.

На пути к веб-разработке.

Жажда, жажда…

 Внимание: не будет ни строчки кода. Только слепок текущего состояния моих мыслей,  размышления о жизни и (будущей) работе.

  Долгое время мне приходилось писать WinForms приложения, лопатить тонны кода хранимых процедур и заниматься разными побочными языками вроде x++. Каждый раз наступал момент, когда работа исчерпывала себя, и душа требовала свежего ветра. Сейчас пишу сервисы на C#, а жажда свежего ветра потихоньку начинает брать своё. В .NET мире осталась одна нехоженая мню дорога – Веб. Весьма востребован в наши дни. Это не попытка открыть Америку, а предисловие к тому факту, что долгое время я пытался ее обплыть стороной. Пришло время и мне стать Колумбом.

Возможно, самый удачный вариант – начать изучение протокола HTTP. Но логика прагматика подсказывает мне, что лучше остановится на одном из доступных фреймворков. Сделать выбор непросто. После официальной работы, и домашних забот остаётся не так уж много времени для работы над собой. Тратить нужно осторожно, на всё не хватит. Я вижу несколько интересных игроков на .net web-арене.

Кто следующий?

 ASP.NET MVCx – самый монструозный и самый популярный фреймворк, обязанный своей популярностью маркетингу (и умению копировать) Microsoft. Сотни вакансий  по сравнению с абсолютным  нулём для всех остальных конкурентов вместе взятых. Казалось бы идеальный выбор, но… Во-первых, Microsoft в очередной раз не изобрела ничего нового, а лишь ответственно подошла к копированию и модернизации Castle Monorail (на тот момент возможно лучший фреймворк для веб). Увы, вместе с достоинствами прихватили и недостатки: необходимость наследовать инфраструктурные классы контроллеров, и возвращаемые мутные ActionResult. Во-вторых, тяготы работы с “корпоративным” фреймворком – скачай то, доставь это, настрой сё и т.д. и т.п. Почему я не могу просто написать Install-Package, и насладиться красотой Hello World по asp.net-овски?  Увы, из-за популярности на рынке мне придётся им заняться, хотя совсем-совсем не хочется. Этот как рыбий жир: противно, но полезно.

 FubuMVC – собственно, не только веб-фреймворк, но и несколько сопутствующих проектов. Вкратце, своё отношение могу высказать фразой “я Пастернака не читал, но одобряю”. Фреймворк построен не тех принципах, которые мне очень близки: Convention Over Configuration, POCO и многое-многое другое, что позволяет освободиться от инфраструктурной тягомутины, и писать собственно приложение. Chad Myers хорошо написал, почему я (заочно) люблю FubuMVC. Не только Chad Myers, а вообще весь состав разработчиков внушает мне полное доверие. Будучи давним читателем CodeBetter, полностью разделяю их подходы, и философию программирования. Fubu точно займёт своё место в моём учебном плане.

 OpenRasta – темная лошадка в моём списке. Не подумайте, он неплохо документирован, и уже достаточно давно обживает белый свет. Но есть есть нюансы. Почти весь фреймворк написал Sebastian Lambla. Себ без сомнений круче Чака Норриса, но всё-таки не Брюс Всемогущий. Не успевает наводить марафет, что частенько вводит в расстройство даже опытных бойцов. Кроме того, у Себа свой особый взгляд на версионирование и управление зависимостями. Они не плохи, просто левая резьба: свои преимущества есть, но  пока не готов бросится вплавь против течения.

 NancyFX – наиболее легковесный, с хорошей документацией и растущим сообществом. Не могу сказать много, но беглый взгляд по документации оставил самые радужные впечатления: всё выглядит понятным, даже для не самого опытного веб-разработчика вроде меня. И это весьма, весьма радует. Похоже, именно Nancy возглавит моё движение в веб.

Легко в учении.

Учить документацию смысла нет – нужна практика. Вот целях обучения напишу скромное двух-трёхзвенное приложение, веб-интерфейс для которого попробую реализовать на заслуживающих внимания фреймворках. Бек-енд тоже не обойдётся без освоения нового – модные ныне CQRS и Event Sourcing уже давно тешат воображение. Пора оседлать их в реале. О своих успехах постараюсь рассказать на страницах блога.