Вышел финальный релиз 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 в файле конфигурации и легко может быть заменен на любой другой.
понедельник, 28 апреля 2008 г.
Enterprise Logging system. Part2 Context.
Перед тем как писать о сервисе коротко опишу контекст, передаваемый ему (сервису) вместе с сообщением. Контекст входит в data contract сообщения LogBook, т.е. я не использую появившийся в .Net 3.5 xxxContextBinding по той простой причине, что однажды установив его уже нельзя будет изменить. Да и передавать контекст в заголовке сообщения также не вижу особого смысла, поэтому он уютно располагается в теле сообщения.
Контекст в LogBook передается в виде словаря Dictionary<string, object>
Чтобы облегчить себе жизнь я написал класс LogContext. LogContext имеет implicit operator конвертирующий его в Dictionary, поэтому не надо делать явных приведений типов.
У него есть свойство Current, которое возвращает текущий контекст (собирает небольшой набор данных об окружении) и несколько методов, с помощью которых его можно расширить.
Эти методы написаны в семантике “fluent interface”, каждый из которых возвращает копию исходного контекста с добавленными свойствами.
public LogContext AddAttributes(IDictionary
public LogContext AddAttribute(string name, object value)
и создание нового расширенного контекста будет выглядеть следующим образом:
var context = LogContext.Current.AddAttribute("1", 1)
.AddAttribute("datacontract", new Class1 { MyProperty = 1})
.AddAttribute("serializable", new Class2 { MyProperty = 2}); - очень удобно!
для того, чтобы передавать в контексте свои «кастомные» объекты, необходимо проделать следующее:
1. Пометить эти классы одним из атрибутов : Serializable или DataContract;
2. Сконфигурировать DataContractSerializer на клиенте и на сервере, добавив в конфигурационный файл приложения следующий блок:
<dataContractSerializer>
<declaredTypes>
<add type="System.Collections.Generic.Dictionary`2,mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<knownType type="ContextSendingTest.Class1, ContextSendingTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<knownType type="ContextSendingTest.Class2, ContextSendingTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Далее при добавлении атрибута контекст проверит, помечен ли класс одним из упомянутых атрибутов и сконфигурирован ли DataContractSerializer.
Контекст реализует интерфейс IEquatable, сравнивая коллекции аттрибутов с использованием дефолтных EqualityComparer, поэтому «кастомные» классы должны перегружать метод Equals для того чтобы изменить логику их сравнения и сравнения контекстов в целом.
Вот, вкратце так.
Удачи!
понедельник, 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 - локальная стратегия кеширования, которая подключается в процессе конфигурирования.

На этом сегодня все в следующий раз подробнее о сервисе.
Удачи.
пятница, 11 апреля 2008 г.
ConfigurationElement serializing unrecognized attributes


вторник, 1 апреля 2008 г.
Enterprise Library 4
Вышел CTP Enterprise Library.
линк для скачивания: http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=entlib&ReleaseId=12142
Удачи.
Loosely-coupled WCF service
- базовый класс сервиса, для доступа к адаптеру;
- поведение, применяемое к сервису, для создания адаптера;
- конфигурационной элемент, для настройки поведения в конфиге;
Далее, для каждой конкретной реализации необходимы:
- интерфейс адаптера, который будет выполнять необходимую сервису работу;
- класс, реализующий интерфейс адаптера;
- класс, реализующий контракт сервиса, унаследованный от базового класса с адаптером.
Вот и все теперь по частям:
ServiceAdapterBase
Базовый класс, инкапсулирующий логику получения объекта адаптера из инфрастуктуры WCF.
Здесь мое главное усовершенствование. Адаптер впервые создается при первом обращении к нему из методов контракта. Такое решение позволяет добиться следующих преимуществ:
- сервис сам управляет временем жизни адаптера (экземпляр адаптера существует в каждом экземпляре сервиса, соответственно их времена жизни равны);
- при установке ServiceBehavior.InstanceContextMode = Single становится невозможным создать адаптер, при поведении применяемом в конфигурационном файлеб ниоткуда кроме текущей операции, т.к. при создании объекта singlton-сервиса инфраструктура wcf еще не инициаллизирована и поведение применяемое в конфиге позволяет расширить wcf только на уровне сервиса или endpoint.
AdapterAttribute - service behavior
Класс, реализующий интерфейс IServiceBehavior, с помощью которого наше поведение подключается к инфраструктуре WCF. Ничего не делает, просто предоставляет данные, необходимые для создания сервиса. Т.к. наше поведение реализовано в классе атрибута, то оно может применяться и декларативно - в коде.
ServiceAdapterBehaviorElement
Класс, необходимый для подключения поведения в файле настроек.


Обратите внимание на параметр типа ServiceAdapter в ServiceAdapterBase - здесь вы можете жестко в коде прошить класс адаптера (удобно для разработчика - можно быстро менять реализацию сервиса). Для того чтобы дать понять классу ServiceAdapterBase, что конкретный тип адаптера будет задан в конфиге ему подставляется затычка - ConfigurableAdapter (пустой класс даже картинку не буду вешать).
И теперь последняя деталь - файл конфигурации:

P.S. С выходом .Net framework 3.5 та же функциональность слегкостью может быть достигнута при помощи модели WorkflowServices и loose-xoml. Почитайте у Roman'а http://www.codeproject.com/KB/WF/VirtualServiceForESB.aspx
Удачи!










