понедельник, 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 attributes)
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 на клиенте и на сервере, добавив в конфигурационный файл приложения следующий блок:

<system.runtime.serialization>
<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 для того чтобы изменить логику их сравнения и сравнения контекстов в целом.

Вот, вкратце так.

Удачи!

Комментариев нет: