понедельник, 11 октября 2010 г.

Applying monadic combinators to build simple parser

After reading this article, it dawned on me, how easy it might be to write parsers using internal dsl syntax. Looks a bit clumsy in C#, yet rather expressive.

I've used wonderful Magnum library built by Dru Sellers and Chris (creators of open source service bus MassTransit project) as a foundation, since it already contains a base for monadic parsers.

As an example, look how easy it is to write a parser for following simple grammar, describing file version structure:

<version> ::= <part>{<delim><part>|<part>}
<part> ::= <positive integer>+ | <letter>+
<delim> ::= “.” | “,” | “(” | “)” | “ “

And parser in mere 10 lines of code:



Good luck!

среда, 29 сентября 2010 г.

Dependency injection Presentation

На слайдах ниже вы найдете презентацию, которую недавно я провел для своих коллег. Цель ее - завлечь в свою религию, шутка, продемонстрировать наглядно преимущества применения DI вживую. Для оживления презентации, используйте код, выложенный здесь.

Dependency injection

P.S. В английской версии блога, я немного порассуждал на тему того, какие "умницы" и как я рад видеть их новые инструменты, но повторяться мне лень . =)

Удачи!

воскресенье, 29 августа 2010 г.

My two cents in OSS. Free VOIP .Net library!

Мои поздравления всем! Только что в сфере .Net стало одной бесплатной VoIP библиотекой больше. Эта библиотека - моя обертка над C-библиотекой pjsip, точнее над ее высокоуровнем API pjsua (user agent).

Работа над ней еще продолжается, но код используется в проектах компании DoxWox, которой выражается отдельное спасибо за возможность опубликовать его. В частности, эта библиотека используется для реализации голосовых конференций в приложении для online общения.

Прошу любить и жаловать: http://code.google.com/p/pjsip4net/

Введение можно почитать здесь:
http://bobbbloggg.blogspot.com/2009/04/designing-managed-api-over-flat-native.html

Частично я уже описывал решения, которыми я руководствовался при создании этой библиотеки, но я планирую более подробно описать здесь внутренности библиотеки, одновременно проводя ее рефакторинг (я, кажется уже упоминал, что работа над ней продолжается ;). Ниже можно почитать о некоторых решениях, примененных в коде:
http://bobbbloggg.blogspot.com/2009/10/detached-template-method-pattern.html
http://bobbbloggg.blogspot.com/2009/09/fluent-builder.html
http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html

Удачи!

понедельник, 9 августа 2010 г.

Windsor Castle BuildUp

Некоторое время назад я обнаружил, что в лучшем DI-контейнере в .Net сфере Windsor Castle (это мое мнение не подтвержденное никакими фактами, кроме моих высказываний) нет такой простой функциональности как BuildUp. Некоторые из существующих DI-контейнеров, имеют такой метод, а Castle нет. Это неспроста. Я считаю, что BuildUp - это костыль для ситуаций, имеющих более элегантное решение, но бывают случаи, когда он оправдывает себя. Например, когда скорость решения проблемы важна. Под более элегантным решением я понимаю интеграцию с DI-framework, как, например, Castle WCF facility, но понимаете сами, сколько времени и ресурсов нужно для создания полноценного решения.

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

Итак, прежде всего нужно ознакомиться с возможностями расширения Castle. Лазейка для BuildUp - это ComponentActivator. Активаторы вызываются при необходимости создать объект LifetimeManager'ами. Отсюда ограничение решения - с SingletonLifetimeManager оно работать не будет, но и не должно, если подумать. Устанавливая время жизни Singleton вы таким образом явно декларируете, что объектом (коего будет только один экземпляр) владеет контейнер, и создает его он же. А потому BuildUp для такого объекта - вещь бессмысленная.



BuildUpComponentActivator наследуется от DefaultComponentActivator и переопределяет только один метод - Instantiate. В этом методе мы извлекаем уже существующий и созданный вне контейнера экземпляр из контекста. Если в контексте его нет, то мы делегируем работу по созданию объекта базовому классу.

В контекст он помещается в методе расширении контейнера BuildUp как дополнительный параметр в IDictionary:



Для того, чтобы объект мог быть пропущен через BuildUp, в компонентной модели для него следует установить ComponentActivator. CanBeBuiltUp оборачивает такой вызов для castle Fluent registration API.

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

Удачи!

четверг, 24 июня 2010 г.

Trigger Caliburn action status update through Prism's IEventAggregator

И Caliburn и Prism, в принципе решают одни и те же задачи - создание композитных приложений на WPF. Но, вот Роб Эйзенберг (создатель Caliburn) не считает, что они друг друга взаимоисключают, а я и подавно с ним согласен.
Я использую следующие "фичи" Prism'a:

  • modularity;
  • region manager;
  • event aggregator;
, а из Caliburn следующие:
  • actions engine;
  • application & model framework, даже не смотря на то, что с первого взгляда model framework кажется "overarchitected";
  • convention over configuration;
Вот сейчас я вам расскажу как расширить actions в Caliburn, при помощи Event Aggregator из Prism.
Главный способ расширения - это написание фильтров, которые вставляются в последовательность выполнения action. С их помощью можно проверять предусловия или состояние данных (к примеру можно проверить обладает ли Principal достаточными правами для выполнения действия), дабы определить статус action и обновить эффекты, применяющиеся к UI элементам. Примером такого фильтра является поставляющийся с framework фильтр Dependencies, который вызывает исполнение всей последовательности фильтров, на основании изменения какого-либо свойства, имя которого передается в качестве параметра ему. Но что, если вам нужно просто обновлять статус action, не связанный ни с каким полем в объекте, на основании какого-либо события/условия. Вы можете завести специальное поле и передергивать его значение или даже еще лучше - не заводите никакого поля, а просто кидайте нотификацию с именем несуществующего поля, переданного фильтру. Не знаю как вам, а у меня от таких решений зудит в одном месте.

Так вот зуд мой унялся только когда я написал фильтр, запускающий всю цепочку обработки статуса события по получению уведомления от EventAggregator сервиса Prism.

DependsOnEvent




Фильтр применяется как атрибут, которому передается тип события. Тут есть одно ограничение - событие должно быть унаследовано от generic типа CompositePresentationEvent закрытого типом object, т.е. CompositePresentationEvent_Of_Object. В методе Initialize происходит магия с помощью reflection. Дело в том, что IEventAggregator Prism имеет исключительно generic интерфейс, за что можно разработчиков его только поругать. Мы получаем событие переданного типа и
подписываемся на него. Вот именно для этого и приходится колдовать с волшебным зеркальцем, т.к. заранее тип события не известен. Часть, относящуюся к запуску обработки action, я содрал из кода упомянутого выше Dependencies фильтра.


Здесь мы создаем Observer, который будет следить за изменениями зависимых свойств. Т.к. реально никакие свойства не меняются я просто использую трюк с несуществующим свойством - в Initialize при подписке на событие я передаю делегат, который кидает событие обновления свойства Update, которого-то как раз и нет. Observer, поймав это событие запускает всю цепочку обновления статуса action.




PublishEventAfter
Ну и напоследок, фильтр, выполняющий все ровно наоборот, после выполнения action он кидает событие, которое обрабатывает EventAggregator.




Удачи!

пятница, 7 мая 2010 г.

Plant your Redis into Windows.

Redis - это OSC проект, представляющий собой высокопроизводительное key-value хранилище данных. Это вполне зрелый проект, используемый в реальных проектах в production. Написан он на Си, и основные целевые платформы - Linux, *BSD, Mac OS X, Solaris. Казалось бы такой хороший и такой недоступный (для Windows)? Ан нет, мало того что ServiceStack собрали и распространяют дистрибутив под Windows (работает через cygwin), так они еще и клиентскую .Net библиотеку написали! Но опять есть одно но - сервер работает в виде консольного приложения, что не очень-то подходит для сервера баз данных. Нужно захостить его в Win32 сервисе, но как?

Очень просто:


Берем OSC проект TopShelf - легкий framework для создания Win32 сервисов, берущий все сложности на себя, и пишем хост-сервис, который будет запускать и останавливать наш сервер.

Посмотрите, win32 сервис буквально в 10 строк кода.


Но, а как же насчет консольного окна? А просто - обратите внимание на аргумент передаваемый процессу сервера Redis (redis.conf). Это имя конфигурационного файла. В нем можно изменять любые настройки сервера. В частности там есть пункт daemonize, который на Linux запускает сервер в виде демона, на Windows же запуск с этим параметром приводит к созданию процесса без окна. И еще одно - x.RunAsLocalSystem();

Вот и все. Теперь запускаем собранный проект из командной строки с аргументами: {project.exe} service install, - и смотрим как все по волшебству происходит само. Теперь это полноценный Win32 сервис, можно запускать.

Удачи!