Вышел финальный релиз Enterprise Libary 4.0, который интегрирован с IoC framework Unity (в предыдущем релизе он не использовался поумолчанию) http://blogs.msdn.com/agile/archive/2008/05/16/enterprise-library-4-0-for-visual-studio-2008-released.aspx. Unity же был обновлен до версии 1.1. http://blogs.msdn.com/agile/archive/2008/05/16/unity-refresh-v1-1.aspx
В Enterprise Library сохранены все интерфейсы предыдущего релиза (3.1), проведена оптимизация (особенно в Logging AB), поддержка WMI 2.0, интеграция с Unity (см. выше), багфиксинг.
Удачи.
понедельник, 19 мая 2008 г.
Enterprise Library 4 final release with Unity integration
среда, 30 апреля 2008 г.
Enterprise Logging System. Part 3. Service.
Сервис - это ядро всей системы. Это последняя инстанция, где кончают свой путь сообщения логов из всех приложений. =)
- централизовать хранение настроек;
- помещать сообщения в сконфигурированное хранилище.
Для того, чтобы сервис мог десериализовать сообщения классов-наследников базовый класс необходимо пометить атрибутами [KnownType(typeof(...))], где ... - имена классов наследников.
Вот классы, являющиеся метаданными системы:

Клиент идентифицируется по запросу, из полей которого составляется уникальный хеш. По нему то и ведется поиск в базе.
Сохранение сообщений делегируется адаптеру системы логирования, который подключается к сервису в файле конфигурации хоста сервиса. Я писал об этом здесь: http://bobbbloggg.blogspot.com/2008/04/loosely-coupled-wcf-service.html. В системе поумолчанию используется адаптер Enterprise Library Logging AB. Так как логи должны сохраняться в надежном хранилище с возможностью репликации со всеми данными системы на основной сервер, то конечно же в роли этого хранилища выступает БД. Дабы не тащить за собой Data Access AB из Enterprise Library, т.к. мне совсем не нравится его реализация, я написал свой легковесный custom DBTraceListener, сохраняющий логи в БД при помощи класов Linq2Sql. Этот TraceListener подключается к Logging AB в файле конфигурации и легко может быть заменен на любой другой.
понедельник, 21 апреля 2008 г.
Enterprise Logging system. Part1 Architecture.
Имею желание поделиться с вами своим взглядом на дизайн системы логирования масштаба предприятия.
"О чем этот сумасшедший?"
Я о той части SOA инфраструктуры, которая отвечает за логирование событий в enterprise. С началом разработки данной системы мы начинаем лавировать в сторону настоящей SOA инфраструктуры, малыми галсами приближаясь к нашему видению такой модной нынче SOA концепции как ESB.
"Точно двинутый, ничего не понятно же".
Да блин, все просто - нужна система, в которую централизовано будут сваливать свои логи все приложения, работающие в сети одной компании.
Итак задачи, ограничения и требования к данной системе:
- должна быть предельно проста в применении разработчиками;
- должна функционировать в распределенной системе - конечная точка сервис;
- возможность работать в отключенном режиме;
- нельзя расчитывать на то, что на клиенте будет установлен SQL сервер, поэтому должна быть возможность подключать различные стратегии кеширования;
- возможность подключения различных библиотек логирования;
- возможность настройки уровня, категорий и пр. данных сообщений, которые будут отправляться с клиента;
- сохранение логов в БД сервера, с тем чтобы реплицировать их с остальными данными на основной сервер;
- возможность настройки альтернативного хранилища/цели сообщений логов (e-mail, event log…) (при помощи сторонних библиотек логирования);
- возможность передать некий контекст;
- управление исходящим траффиком
- ...
Теперь обратимся к литературе. На codeproject я нашел несколько статей, в которых описано решение подобных задач:
- http://www.codeproject.com/KB/WPF/WpfLogging.aspx
- http://www.codeproject.com/KB/silverlight/SilverlightLogging.aspx
В статьях предлагается уже готовое решение - библиотека для логирования с возможностью ведения логов на сервере. В принципе это решение могло бы устроить, но в нем не реализовано одно из основных требований - возможность работы в отключенном режиме. К слову сказать, в данной библиотеке можно реализовать подобное поведение, но это для этого потребовалось бы дописывать некоторое количество кода. Да к тому же, держа в голове тот факт, что в конце концов данная библиотека будет интегрирована в нашу SOA инфраструктуру, лучше иметь полный контроль над кодом. Поэтому я принял решение не использовать данную библиотеку, но несколько светлых идей оттуда почерпнул. В частности модель провайдеров для подключения локальной стратегии и модель фильтров для управления исходящим трафиком.
В качестве стронней библиотеки логирования я рассматривал следующие проекты:
- NLog http://www.nlog-project.org/;
- log4net http://www.nlog-project.org/;
- Enterprise Library Logging Application Block http://msdn2.microsoft.com/en-us/library/cc309506.aspx;
Функциональность и модель программирования во всех этих проектах примерно одинаковая и включает в себя возможность логировать в такие хранилища как Event log, база данных, E-mail, и т.д. и т.п. В конечном итоге выбор я остановился на Enterprise library, во-первых потому что я уже имею опыт работы с Enterprise Library и использовал Validation Application Block в слое бизнес объектов в проектах (писал об этом здесь), а во-вторых чтобы сохранить единую базу, на которой строятся все проекты.
После обработки материалов и требований у меня сложилась следующая архитектура.

Характерными особенностями ее являются:
- логирование всегда ведется на сервере, поэтому сервис логирования является основной компонентой системы;
- сервис слабо связан с непосредственным кодом логирования и библиотекой, берущей на себя эти функции при помощи уже описанного мною приема http://bobbbloggg.blogspot.com/2008/04/loosely-coupled-wcf-service.html; Это оставляет за мной возможность безболезненно сменить библиотеку логирования, в случае, если звезды изменят свое расположение и я передумаю использовать Logging AB;
- клиент работает с библотекой через фасад, а всю работу по конфигурированию, кешированию и работе с сервисом система берет на себя прозрачно для клиента, при этом по возможности не блокируя его;
- сервис логирования - WCF singleton-сервис; Его функция централизовывать хранение настроек и делегировать сохранение сообщений адаптеру библиотеки логирования;
- сохранение логов в базу данных производится через подключаемый к Logging AB Custom TraceListener.
Сообщения в системе имеют несколько уровней, которые в порядке приоритета распологаются в следующим образом:
- Trace;
- Info;
- Warn;
- Error;
- Status;
Настройки клиентов, уникально себя идентифицирующих, хранятся в БД. При первом обращении к фасаду системы, клиент обращается к сервису с просьбой передать настройки, если сервис недоступен - пытается "поднять" их из локального конфига.
Локальные стратегии кеширования подключаются к клиентской части системы при помощи модели провайдеров ASP.NET. Так же система расширяется за счет подключаемых фильтров, которые контролируют исходящий траффик. По умолчанию в систему включены провайдер локальных стратегий, стратегия кеширования в оперативной памяти (для тестирования), стратегия для кеширования в IsolatedStorage, фильтр траффика по уровню сообщения.
В серверной части система расширяется при помощи модели расширений WCF, подключая к сервису адаптер, которому делегируется работа с библиотекой логирования. В систему встроен адаптер для работы с EnterpriseLibrary.
Всю работу по отправке сообщений в сервис берет на себя компонента системы Disconnected Service Agent (DSA). В Smart Client Software Library есть Application Block, реализующий данную функциональность, но по упомянутым выше причинам я предпочел не использовать готовую функциональность, а написал свой небольшой блок, опять же почерпнув из MS-ской реализации светлые идеи. Основными частями данного блока являются:
- Connection Monitor - агент, который следит за состоянием подключения к сервису;
- Request Manager - диспетчер запросов. Ставит запросы в очередь (локальную стратегию кеширования), пытается асинхронно отправить их, дабы не блокировать клиента;
- Local Store Strategy - локальная стратегия кеширования, которая подключается в процессе конфигурирования.

На этом сегодня все в следующий раз подробнее о сервисе.
Удачи.
вторник, 1 апреля 2008 г.
Enterprise Library 4
Вышел CTP Enterprise Library.
линк для скачивания: http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=entlib&ReleaseId=12142
Удачи.
вторник, 4 марта 2008 г.
Business objects validation and UI integration
Случилось мне писать WPF Wizard. И было это сложно и интересно и много проблем порешал я.
- автоматическое отслеживание представлениями состояния валидности объекта (кнопки Next, Save и т.п. должны быть отключены, если редактируемый объект в невалидном состоянии, и наоборот. Проще говоря, wizard не должен дать вам совершить ошибку);
- прозрачное для разработчика валидирование - это не должна быть его забота и он не должен писать в code-behind никакой логики валидирования;
Что есть:
- В WPF binding engine есть валидация. Она реализуется при помощи объектов классов наследников ValidationRule и статического класса Validation. Почему бы не использовать их и не угомониться на этом? Да потому что это валидация данных, лежащих в UI контролах, а не валидация бизнес объектов. Нужен унифицированный механизм, не завязанный на UI технологию, т.к. валидровать объект можно не только в UI. Но эту технологию можно использовать как точку расширения и подключения дополнительной логики в процессе валидирования данных wizard.
- В Enterprise library (EL) есть Validation Application Block (VAB), который предназначен для решения задачи валидирования бизнес-объектов;
- В предыдущих постах я писал об использовании комманд WPF, управляющих состоянием UI.
- на первой странице заполняются ФИО, причем имя или фамилия поля обязательные.
- на второй странице заполняются настройки доступа - логин, пароль, подтверждение пароля
- на третьей странице заполняется и так далее... =)
- ObservableObject - уже встречавшийся нам класс, реализующий InotifyPropertyChanged.
- DomainObject - базовый класс домена. Содержит шаблонный метод DoValidate, в котором наследниками должна будет реализовываться логика валидирования. Не является data contract, но помечен аттрибутом [Serializable]. Такое решение принято чтобы не вводить зависимость домена от технологии создания сервисов (WCF).
- DomainDTO - базовый класс для всех дата контрактов. Знает обо всех своих наследниках (при помощи аттрибута [KnownType]).
- DomainDTO
, где Т - тип класса наследника. Реализует логику валидирования объекта.
Базовый класс домена.
Как видите класс не сериализует результаты валидирования, ибо нет нужды передавать их через границу сервиса.
Базовый дата контракт, реализующий шаблоный метод.
DomainDTO
Здесь он просит фасад VAB фабрики объектов создать композитный валидатор по указанному ruleSet подмножеству, а затем передает себя валидатору, который собирает, комбинирует и возвращает ответ от всех валидаторов, входящих в указанный validationRuleSet.
В wizard'е есть следующие команды:
- NextPage - переход на следующую страницу;
- BackPage - переход на предыдущую страницу;
- GoToPage - переход на указаную страницу;
- Save - сохранить редактируемый объект;
- Cancel - отменить редактирование объекта;
- Help - показать файл справки;
Для демонстрации этой возможности представьте себе следующий сценарий:
на странице wizard'а редактируется объект пользовательских данных для разграничения доступа (логин, пароль). На странице есть 1 TextBox - Login, и 2 PasswordBox'а - Password, PasswordConfirmation. В DataContext страницы wizard'а лежит бизнес-объект (пусть LoginCredential). Поле Text textbox'а Login привязано (binding) к свойству LoginCredential.Login, поле Text passwordbox'а Password в codebehind привязно к LoginCredential.Password. Для валидации данных, необходимо, чтобы пользователь повторил пароль, но в объекте LoginCredential нет поля повтор пароля. Если в passwordbox PasswordConfirmation не будет введен идентичный первому пароль все навигационные кнопки не должны быть активными. Как быть? Мы по-прежнему не хотим писать spaghetti-code.
Здесь и вступает в игру binding validation, ведь теперь мы валидируем не бизнес объект, а данные, которые лежат в UI, но сильно влияют на принятие решения о валидности объекта.

Также у класса есть attached-свойство Bag, которое будет очень полезно объектам у которых нет dependency-свойств, чтобы привязывать какие-либо данные через WPF binding.



Логика очень проста - если пароли различны, то при помощи вспомогательного метода ValidationHelper.MarkInvalid страница помечается невалидной и в OnQueryEnabled будет принято решение о невалидности данных,т.к. страница невалидна. Если же введенные пароли идентичны, то страница помечается валидной вспомогательным методом ValidationHelper.ClearInvalid.















