Использование сервисов оповещения в SQL Server 2005 Из-за сложных опций конфигурирования может быть несколько сложно приступить к написанию приложений SQL Server 2005 Notification Services (SQLNS, сервис оповещения), но как только станут понятными концепции и идеи, стоящие за SQLNS, вы сможете писать солидные приложения, одновременно масштабируемые и расширяемые, используя общие интерфейсы. Каждый день при помощи SMS сообщений мы получаем множество уведомлений: прогноз погоды, новости, котировки акций, текущий баланс счета. Каким образом подобные приложения оповещений можно построить на платформе Microsoft? Есть две возможности: первая и наименее приятная – строить такое приложение с нуля. Вторая, наиболее привлекательная возможность, – использовать SQL Server 2005 Notification Services (SQLNS), являющиеся новым API, помогающим при построении приложений оповещения. SQLNS позволяет генерировать и доставлять оповещения тысячам конечных пользователей приложения несколькими различными способами и вне зависимости от локального времени машины, получающей уведомление. Один из наиболее известных протоколов доставки оповещений - это электронная почта, как наиболее привычный способ работы. Но в SQLNS можно использовать не только e-mail, но также осуществлять оповещение посредством SMS, пейджера или клиента Windows Messenger. Если этих возможностей покажется недостаточно, можно также создать свой собственный канал доставки. 1. Архитектура SQLNS основаны на четырех компонентах, формирующих центральную часть SQLNS приложения. SQLNS приложения всегда обслуживаются SQL Server-ом или Windows Service-ом. В таблице 1 описаны эти четыре главных компонента. Таблица 1. Четыре главных компонента, необходимых SQLNS приложению, с описанием каждого из них. Компонент Подписчик Subscriber Описание Подписчик – это лицо или приложение, которое желает получать оповещения. Подписка Subscription Подписка – это запрос на оповещение, может генерироваться из приложения посредством SQLNS API. Типичный пример – изменение курса акций. Событие Event Событие – это информация, в которой заинтересован подписчик. При изменении стоимости акций может генерироваться событие, которое обрабатывается внутри SQLNS. Оповещение Notification Компонент оповещения – это уведомление, которое посылается зарегистрированному подписчику через определенный канал доставки. Рисунок 1 показывает, каким образом объединяются эти компоненты в SQLNS приложении. Всякий раз для генерирования нового оповещения и доставки его зарегистрированным подписчикам, SQLNS выполняет следующие шаги: Рис. 1. Основные компоненты SQLNS приложения. Пользователи подписіваются на получения оповещений с помощью приложений управления подпиской, таких как внешний интерфейс ASP.NET или Windows Forms. Управление подпиской – это единственная часть SQLNS приложения, в которой пользователи или приложения активно вовлечены в процесс. Вы генерируете подписки, используя управляемые сборки, устанавливаемые с SQLNS. Notification Application (приложение оповещения) собирает события, которые обрабатываются внутри SQLNS приложения. SQLNS использует операторы T-SQL, чтобы назначить события подпискам, зарегистрированным в первом шаге. SQLNS генерирует новые оповещения каждый раз, когда находит такое назначение. Formatter форматирует новое оповещение, и SQLNS доставляет его по каналу доставки к зарегистрированному целевому устройству подписчика. Как видите, SQLNS приложения выполняются полностью внутри SQL Server, за исключением лишь процесса регистрации подписки. 2. Файлы конфигурации SQLNS Чтобы связать все компоненты вместе, необходимо воспользоваться парой файлов конфигурации, основанных на XML: файла Instance Configuration и файла Application Definition. Чтобы захостить SQLNS приложение, необходим экземпляр SQLNS. Экземпляр SQLNS может обслуживать одно или более SQLNS приложений. Экземпляр также хранит информацию о подписчике, которой может делиться с другими SQLNS приложениями, размещенными на экземпляре. Файл конфигурации экземпляра, Instance Configuration File, регистрирует каждое SQLNS приложение для этого экземпляра. Вот пример файла конфигурации экземпляра (Instance Configuration File). <?xml version="1.0" encoding="utf-8" ?> <NotificationServicesInstance xmlns="http://www.microsoft.com/MicrosoftNotificationServices/Con figurationFileSchema"> <InstanceName>DM</InstanceName> <SqlServerSystem> Localhost </SqlServerSystem> <Applications> <Application> <ApplicationName> StockPrice </ApplicationName> <BaseDirectoryPath> C:\MyPath </BaseDirectoryPath> <ApplicationDefinitionFilePath> appADF.xml </ApplicationDefinitionFilePath> </Application> </Applications> <DeliveryChannels> <DeliveryChannel> <DeliveryChannelName> FileChannel </DeliveryChannelName> </DeliveryChannel> </DeliveryChannels> </NotificationServicesInstance> В таблице 2 приведены наиболее важные XML элементы, используемые в этом файле конфигурации. Таблица 2. Описание основных элементов файла конфигурации экземпляра Instance Configuration file. XML элемент InstanceName Описание Имя этого SQLNS экземпляра. SqlServerSystem Имя SQL Server-а, который обслуживает базу данных SQLNS экземпляра. DeliveryChannel Описывает несколько каналов доставки, поддерживаемых этим экземпляром SQLNS. Для каждого приложения, размещенного на этом экземпляре, внутри секции <Applications> должна располагаться секция <Application>. Внутри каждого элемента <Application> осуществляется конфигурирование XML элементов, показанных в Таблице 3. Таблица 3. XML элементы, необходимые каждому элементу <Application> в файле конфигурации экземпляра Instance Configuration file. XML элемент ApplicationName Описание Имя SQLNS приложения, выполняющегося на этом SQLNS экземпляре. BaseDirectoryPath Основная директория SQLNS приложения. Здесь хранится вся относящаяся к приложению информация, в том числе Application Definition File. ApplicationDefinitionFilePath Имя и путь к Application Definition File, который конфигурирует SQLNS приложение. 3. Файл определений приложения (Application Definition File) Более интересен Application Definition File. Этот файл используется для конфигурирования всей структуры SQLNS приложения наряду со всеми необходимыми метаданными. В Листинге 1 приведен минимальный Application Definition File. Как видно из Листинга 1, пример SQLNS приложения поддерживает только одну подписку, с именем StockPriceSubscription. Эта подписка содержит только один существенный элемент информации, StockSymbol, хранимый в столбце таблицы, который предоставляет пользователям интерфейсного приложения возможность доступа к кодам интересующих их акций. SQLNS использует этот файл конфигурации для создания всех таблиц, необходимых SQLNS приложению. В дальнейшем это свойство мы рассмотрим подробнее. С помощью секции <NotificationClass> можно определить структуру оповещений, которые генерирует приложение. В Листинге 1 эта секция пуста, но позже вы ее определите. В данный момент файл конфигурации определяет только то, что для форматирования оповещений будет использоваться XsltFormatter. Для генерирования оповещений используется Generator, а для их доставки зарегистрированным пользователям - Distributor. Секции <Generator> и <Distributors> задают те компьютеры, на которых выполняются эти компоненты, делая возможным распределение компонентов SQLNS приложения между несколькими физическими компьютерами в целях масштабируемости. 4. Использование NSControl.exe После конфигурирования SQLNS экземпляра и приложения, требуется создать все необходимые базы данных, заданные в файлах конфигурации. SQLNS предоставляет средство командной утилиты nscontrol.exe для упрощения этого процесса. Таблица 4 описывает опции nscontrol.exe. Таблица 4. Таблица перечисляет опции командной строки, доступные для nscontrol.exe. Опция Create Delete Disable Enable Register Unregister Описание Создает новый экземпляр SQLNS. Удаляет существующий экземпляр SQLNS. Запрещает экземпляр SQLNS. Разрешает экземпляр SQLNS. Регистрирует новый экземпляр SQLNS. Отменяет регистрацию экземпляра SQLNS. Update Обновляет существующий экземпляр SQLNS. К примеру, для создания нового экземпляра SQLNS вызывается nscontrol.exe с опцией Create и ему передается имя файла Instance Configuration в качестве параметра вызова, таким образом: nscontrol.exe -Create -In Instance.xml Параметр In определяет файл конфигурации экземпляра, который задействует nscontrol.exe. Когда производится такой вызов, nscontrol.exe создает новый экземпляр SQLNS и регистрирует SQLNS приложение с этим новым экземпляром. В дополнение, он создает экземпляр базы данных DMNSMain и базу данных приложения DMStockPrice со структурой, определенной в файле Application Definition File. Эти имена баз данных создаются автоматически с помощью nscontrol.exe и не могут быть перенастроены в какомлибо файле конфигурации. 5. Определение событий Чтобы воспользоваться SQLNS, необходимо определить события, которые SQLNS будет обрабатывать для создания оповещений. SQLNS обрабатывает события из EventProvider, который записывает новые события в таблицу событий. Вам нужно определить классы Event, обрабатывающие вновь поступающие события. Классы Event определяются в секции <EventClasses> файла Application Definition. В Листинге 2 приводится определение класса Event для демонстрационного приложения. В Листинге 2 задается определение только одного события StockEvt. Это событие состоит из свойств StockCode, ExchangeCode и Price. Когда приложение создается или обновляется с помощью nscontrol.exe, создается новая таблица событий для использования SQLNS приложением. Чтобы обработать события, необходим один дополнительный компонент — Event Provider (провайдер событий). Event Provider-ы передают новые события SQLNS для обработки. Провайдеры событий конфигурируются с помощью секции <Providers> в файле Application Definition file, как показано в следующем XML фрагменте. Вершину <Providers> можно расположить в любом месте файла конфигурации. <Providers> <HostedProvider> <ProviderName> StockEP </ProviderName> <ClassName> FileSystemWatcherProvider </ClassName> <SystemName> localhost </SystemName> <Arguments> <Argument> <Name>WatchDirectory</Name> <Value>C:\Events</Value> </Argument> <Argument> <Name>SchemaFile</Name> <Value>Schema.xsd</Value> </Argument> <Argument> <Name>EventClassName</Name> <Value>StockEvt</Value> </Argument> </Arguments> </HostedProvider> </Providers> Секция <Providers>, показанная выше, определяет Event Provider по имени StockEP, использующий встроенный провайдер FileSystemWatcherProvider. Этот провайдер следит за появлением новых файлов в директории. К примеру, в сценарии демонстрационного приложения другое приложение периодически размещает новый файл в папке просмотра WatchDirectory, определенной как C:\Events. Провайдер StockEP наблюдает за этой директорией, обрабатывает события, и производит новые записи в таблицу событий. После добавления секции <Providers> в файл Application Definition file, необходимо обновить SQLNS приложения с помощью nscontrol.exe. nscontrol.exe --Update --in appADF.xml Поскольку FileSystemWatcherProvider – это так называемый Hosted Provider (другое свойство - Non-hosted Provider), вы должны активировать Service Mode на экземпляре SQLNS. Hosted Provider располагается внутри SQLNS экземпляра, Non-hosted Provider может быть размещен в вашем собственном приложении. При этом SQLNS экземпляр выполняется как нормальный Windows Service и наблюдает заданную директорию на предмет появления новых входящих событий в форме XML файлов. nscontrol.exe --Register name DM --server localhost --service При выполнении этой команды nscontrol.exe создает и запускает новый Windows Service с именем NS$DM. SQLNS всегда добавляет префикс NS$, который указывает, что это именно Windows Service, используемый для SQLNS. Префикс имени сервиса нельзя изменить посредством конфигурирования. Поскольку этот сервис является обычным Windows Service, его можно администрировать с помощью стандартного MMC Services интегрируемого приложения. Секция <Providers>, показанная выше, также определяет XSD схему. Все новые файлы событий, записанные в директорию событий, должны быть успешно проверены по отношению к этому файлу XML схемы. Здесь приведено определение файла XML схемы, используемого в демонстрационном приложении: <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sql= "urn:schemas-microsoft-com:mapping-schema"> <xsd:element name="event" sql:relation"StockEvt"> <xsd:complexType> <xsd:sequence> <xsd:element name="StockCode" type="xsd:string" /> <xsd:element name="ExchangeCode" type="xsd:string" /> <xsd:element name="price" type="xsd:decimal" </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> Согласно данной схеме, XML файл события может иметь следующую структуру: <?xml version="1.0" encoding="utf-8" ?> <event xmlns="http://tempuri.org/ XMLSchema.xsd"> <StockCode>MSFT</StockCode> <ExchangeCode>NYSE</ExchangeCode> <Price>60.54</Price> </event> SQLNS обрабатывает такие файлы событий и производит новую запись в таблицу событий приложения, NSStockEvtEvents. 6.Определение подписок Для отсылки оповещений SQLNS должен знать: Кто должен получать оповещения Какую информацию посылать Целевое устройство, на которое должно быть послано оповещение Вы задаете эту информацию с помощью объектов управления подпиской, Subscription Management Objects, из .NET приложения. Subscription Management Objects – это набор .NET классов, реализованных в сборке, устанавливаемой с SQLNS. SQLNS хранит информацию о подписке в базе данных экземпляра (но не в базе данных приложения). Такое проектное решение позволяет использовать информацию подписчика в более чем одном SQLNS приложении. До управления подписками необходимо определить класс Subscription в файле Application Definition. Также необходимо сконфигурировать канал доставки, Delivery Channel, в файле конфигурации экземпляра (Instance Configuration). Класс Subscription хранит информацию о событии, целевом устройстве, и языке, на котором должно доставляться оповещение. В Листинге 3 показан класс Subscription для демонстрационного приложения. Используя именно этот класс Subscription, nscontrol.exe создаст новую таблицу в момент запуска его для обновления экземпляра SQLNS. Столбец DeviceName хранит название устройства, к которому SQLNS будет привязывать подписку. Столбец SubLocale определяет язык, на котором SQLNS посылает оповещение. Используя столбцы StockCode, ExchangeCode и TriggerVal, пользователи могут задать, об изменениях относительно каких акций они хотят быть уведомлены. К примеру, типичный запрос на оповещение может быть таким: "Я хочу быть информированным каждый раз, когда цена акций MSFT (столбец StockCode), которыми торгуют на NYSE (столбец ExchangeCode), превысит $7.00 (столбец TriggerVal)." Приложение управления подпиской Subscription Management должно выполнять три следующие задачи: Создать нового подписчика Задать целевое устройство для нового подписчика Создать подписку для нового подписчика Для взаимодействия с существующим экземпляром SQLNS необходима ссылка на него. В демо-приложении для этого используется объект NSInstance. Конструктор этого объекта получает параметр, содержащий имя SQLNS экземпляра для управления. Класс SubscriberDevice представляет целевое устройство подписчика, а класс Subscription представляет подписку. Обладая такой информацией, легко выполнить все эти три задачи. В Листинге 4 показан требуемый код в C#. Этот самый код можно использовать либо в ASP.NET либо в Windows Forms приложении. Наиболее интересный метод - AddSubscription. Этот метод создает новый экземпляр Subscription, затем применяет его метод SetFieldValue для задания различных свойств Subscription. SQLNS использует эту информацию, чтобы генерировать оповещения из вновь полученных событий. 7. Генерирование оповещений После добавления подписок в базу данных, можно начать генерирование оповещений из вновь поступающих событий. Помните, что SQLNS генерирует оповещения, сравнивая новые события с хранимой информацией о подписке. Точнее, SQLNS только выполняет простой оператор T-SQL JOIN (Notification Rule) между таблицами Events и Subscriptions. Результат этого JOIN – оповещения, которые SQLNS должен отсылать подписчикам. Структуры результирующих оповещений определяются посредством Notification Classes в файле Application Definition, в секции <NotificationClasses>, как показано в Листинге 5. После добавления класса Notification и выполнения nscontrol.exe для обновления экземпляра SQLNS, создается новая таблица оповещений внутри базы данных приложения. И в последнюю очередь необходимо добавить правило оповещения, Notification Rule. Следующий пример показывает, где именно располагать Notification Rule в файле Application Definition. SubscriptionClass> <EventRules> <EventRule> <RuleName>EvtRule</RuleName> <Action> <!&#151;Insert Notification Rule here --> </Action> </EventRule> </EventRules> </SubscriptionClass> Для наглядности правило оповещения (Notification Rule) приводится ниже в отдельном фрагменте кода: INSERT INTO StockPriceNotifications (SubscriberId, DeviceName, SubscriberLocale, StockCode, ExchangeCode, Price) SELECT s.SubscriberId, s.DeviceName, s.SubLocale, e.StockCoce, e.ExchangeCode, e.Price FROM StockEvt e, StockPriceSubscriptions s WHERE e.ExchangeCode = s.ExchangeCode AND e.StockCode = s.StockCode AND e.Price &gt; s.TriggerVal Убедитесь, что здесь вы избежали специальных символов (типа ">"), поскольку Notification Rule записывается в XML файл! Иначе, вы можете поместить Notification Rule в хранимую процедуру. Предыдущий оператор T-SQL вставляет новую запись в таблицу оповещений каждый раз, когда SQLNS получает соответствующее событие, далее оно передает все сгенерированные оповещения в Formatter. Formatter производит форматирование оповещений. SQLNS поставляется вместе с XsltFormatter, используемом в демонстрационном приложении, но для особых случаев можно написать собственный Formatter. С помощью XsltFormatter устанавливается таблица стилей XSLT, которая задает формат оповещения. Formatter определяется в секции <NotificationClass> файла Application Definition. Вот пример: <NotificationClass> <ContentFormatter> <ClassName> XsltFormatter </ClassName> <Arguments> <Argument> <Name> XsltBaseDirectoryPath </Name> <Value> C:\Stylesheets </Value> </Argument> <Argument> <Name> XsltFileName </Name> <Value> Tansformation.xslt </Value> </Argument> </Arguments> </ContentFormatter> </NotificationClass> Как только отформатированы оповещения, последнее, что необходимо сделать, - послать их подписчику. Для этого необходимо задать протокол доставки, Delivery Protocol. SQLNS предоставляет два встроенных протокола, SMTP и File, которые посылают уведомления по e-mail или записывают их в файл. Разработчики часто используют протокол File в тестовых целях. Протоколы доставки конфигурируются в файле Instance Configuration таким образом. <DeliveryChannels> <DeliveryChannel> <DeliveryChannelName> FileChannel </DeliveryChannelName> <ProtocolName> File </ProtocolName> <Arguments> <Argument> <Name> FileName </Name> <Value> C:\Notifications.txt </Value> </Argument> </Arguments> </DeliveryChannel> </DeliveryChannels> После добавления DeliveryChannel, выполните напоследок nscontrol.exe, и приложение оповещения в целом готово к работе. Как только в наблюдаемую директорию помещается новый файл события, SQLNS должно записать результирующее оповещение в файл C:\Notifications.txt. 8. Заключение Дальнейшую информацию о SQLNS можно прочитать в книге Shyam Pather Microsoft SQL Server Notification Services(http://books.internet.com/books/0672326647). Надеюсь, данная статья послужила для вас полным введением в SQLNS, и призываю экспериментировать и видоизменять файлы конфигурации демонстрационного приложения для построения собственных приложений. Листинг 1. Минимальный файл определения приложения (Application Definition File) В файле определения приложения можно конфигурировать полную структуру и все необходимые метаданные для SQLNS приложения <?xml version="1.0" encoding="utf-8" ?> <Application xmlns="http://www.microsoft.com/MicrosoftNotificationServices/App licationDefinitionFileSchema"> <SubscriptionClasses> <SubscriptionClass> <SubscriptionClassName> StockPriceSubscription </SubscriptionClassName> <Schema> <Field> <FieldName> StockSymbol </FieldName> <FieldType> varchar(255) </FieldType> </Field> </Schema> </SubscriptionClass> </SubscriptionClasses> <NotificationClasses> <NotificationClass> <NotificationClassName> StockPriceNotifications </NotificationClassName> </Schema> <ContentFormatter> <ClassName> XsltFormatter </ClassName> </ContentFormatter> </NotificationClass> </NotificationClasses> <Generator> <SystemName> localhost </SystemName> </Generator> <Distributors> <Distributor> <SystemName> localhost </SystemName> </Distributors> </Distributors> </Application> Листинг 2. Определение класса события В Листинге показано определение класса Event для демо-приложения. <EventClasses> <EventClass> <EventClassName> StockEvt </EventClassName> <Schema> <Field> <FieldName> StockCode </FieldName> <FieldType> varchar(10) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> ExchangeCode </FieldName> <FieldType> varchar(15) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> Price </FieldName> <FieldType> decimal(18,5) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> </Schema> </EventClass> </EventClasses> Листинг 3. Пример класса Subscription: В листинге приведено описание класса Subscription для демо-приложения. <SubscriptionClasses> <SubscriptionClass> <SubscriptionClassName> StockPriceSubscriptions </SubscriptionClassName> <Schema> <Field> <FieldName> DeviceName </FieldName> <FieldType> varchar(255) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> SubLocale </FieldName> <FieldType> varchar(10) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> StockCode </FieldName> <FieldType> varchar(15) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> ExchangeCode </FieldName> <FieldType> varchar(15) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> <Field> <FieldName> TriggerVal </FieldName> <FieldType> decimal(18,5) </FieldType> <FieldTypeMods> not null </FieldTypeMods> </Field> </Schema> </SubscriptionClass> </SubscriptionClasses> Листинг 4. Приложение управления подпиской: Эта небольшая .NET программа работает как полное демонстрационное приложение управления подпиской. public static void Main() { AddSubscriber("DM", "Klaus"); AddSubscriberDevice("DM", "Klaus"); AddSubscription(„"DM", „StockPrice", „Klaus"); } private static void AddSubscriber( string instance, string subscriberId) { NSInstance nsInstance = new NSInstance(instance); Subscriber sub = new Subscriber(nsInstance); sub.SubscriberId = subscriberId; sub.Add(); } private static void AddSubscriberDevice( string instance, string subscriberId) { NSInstance nsInstance = new NSInstance(instance); SubscriberDevice dev = new SubscriberDevice(nsInstance); dev.DeliveryChannelName = "FileChannel"; dev.DeviceAddress = ""; dev.DeviceName = "FileDevice"; dev.DeviceTypeName = "File"; dev.SubscriberId = subscriberId; dev.Add(); } private static void AddSubscription( string instance, string applicationName, string subscriberId) { NSInstance nsInstance = new NSInstance(instance); NSApplication app = new NSApplication(instance); Subscription sub = new Subscription(app, "StockPriceSubscriptions"); sub.SetFieldValue("DeviceName", "FileDevice"); sub.SetFieldValue("SubLocale", "en-US"); sub.SetFieldValue("StockCode", "MSFT"; sub.SetFieldValue("ExchangeCode", "NYSE"); sub.SetFieldValue("TriggerVal", 7); sub.Add(); } Листинг 5. Класс Notification Демонстрационное приложение определяет класс Notification в файле Application Definition file. <NotificationClasses> <NotificationClass> <NotificationClassName> StockPriceNotifications </NotificationClassName> <Schema> <Fields> <Field> <FieldName> StockCode </FieldName> <FieldType> varchar(15) </FieldType> </Field> <Field> <FieldName> ExchangeCode </FieldName> <FieldType> varchar(15) </FieldType> </Field> <Field> <FieldName> Price </FieldName> <FieldType> decimal(18,5) </FieldType> </Field> </Fields> </Schema> <ContentFormatter> <ClassName> XsltFormatter </ClassName> </ContentFormatter> <Protocols> <Protocol> <ProtocolFileName> File </ProtocolFileName> </Protocol> </Protocols> <ExpirationAge> PT2H </ExpirationAge> </NotificationClass> </NotificationClasses>