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!
понедельник, 11 октября 2010 г.
Applying monadic combinators to build simple parser
среда, 29 сентября 2010 г.
Dependency injection Presentation
На слайдах ниже вы найдете презентацию, которую недавно я провел для своих коллег. Цель ее - завлечь в свою религию, шутка, продемонстрировать наглядно преимущества применения DI вживую. Для оживления презентации, используйте код, выложенный здесь.
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;
- actions engine;
- application & model framework, даже не смотря на то, что с первого взгляда model framework кажется "overarchitected";
- convention over configuration;
Главный способ расширения - это написание фильтров, которые вставляются в последовательность выполнения 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 сервис, можно запускать.
Удачи!