Разработка распределенных приложений в Microsoft.NET Framework

       

Использование слабо связанных событий


Для использования слабо связанных событий необходимо (рис. 6.7):

  • создать интерфейс, описывающий методы события;
  • создать так называемый класс события (event class), который является особой обслуживаемой компонентой, реализующей указанный интерфейс;
  • создать реализующую этот же интерфейс обслуживаемую компоненту и подписать ее на событие; таких сервисных компонент можно создать несколько и они могут входить в состав различных приложений COM+;
  • написать в издателе код создания события, заключающийся в создании экземпляра класса события и вызова его методов.


Рис. 6.7.  Использование слабо связанных событий

Сначала создается интерфейс, описывающий один или несколько методов событий. Поскольку для подписки на событие необходимо будет использовать идентификаторы класса события и интерфейса, то они описаны как константы.

// LceEvents.cs using System; using System.Runtime.InteropServices; using System.EnterpriseServices; public static class EventsGuids { public const string interfaceId = "A5105B2C-40BF-46C6-B19C-4286A423DBF9"; public const string eventClassId = "DF64D391-CCE9-4FC6-B5F2-3F4DE3FA48C2"; } [Guid(EventsGuids.interfaceId)] public interface ILceMessage { void TriggerEvent(string message); } // LceEvents.cs

Далее описано приложение, являющееся издателем события.

// LcePublisher.cs using System; using System.Threading; using System.Runtime.InteropServices; using System.EnterpriseServices; [assembly: ApplicationName("LCE publisher")] [assembly: ApplicationActivation(ActivationOption.Server)] [assembly: ApplicationAccessControl(false)]

Необходимо описать класс события, используя атрибут EventClassAttribute и описанный ранее уникальный идентификатор. Методы данного класса не содержат кода, класс события нужен только как формальная реализация интерфейса.

[EventClass] [Guid(EventsGuids.eventClassId)] [Transaction(TransactionOption.Disabled)] public class LceEvents: ServicedComponent, ILceMessage { public void TriggerEvent(string message) { } }

Издатель события может быть как обслуживаемой компонентой, так и не быть связанным с контекстом COM+.
Следует учитывать, что при отсутствии у события подписчиков будет выброшено исключение COM+.

public class LcePublisher: ServicedComponent { public LcePublisher() { } public void DoWork() { ILceMessage lcEvent = (ILceMessage) new LceEvents(); try { while (true) { lcEvent.TriggerEvent("Событие!"); Thread.Sleep(1000); } } catch (System.Runtime.InteropServices.COMException) { Console.WriteLine("Нет подписчиков"); } } } class MainApp { public static void Main() { LcePublisher com = new LcePublisher(); com.DoWork(); } } // LcePublisher.cs Подписчик события является компонентой COM+, реализующей интерфейс события. Метод данного интерфейса вызывается при публикации события. В качестве примера при обработке события подписчик проверяет наличие частной очереди сообщений и посылает в нее сообщение, после чего сообщает об успехе транзакции. Для простоты примера имя очереди указано как константа, реальные приложения должны хранить его в файле конфигурации.

// LceSubscriber.cs using System; using System.IO; using System.Threading; using System.Runtime.InteropServices; using System.EnterpriseServices; using System.Messaging; using Seva.ComUtils; using Seva.Msmq; [assembly: ApplicationName("LCE demo")] [assembly: ApplicationActivation(ActivationOption.Server)] [assembly: ApplicationAccessControl(false)] public static class Consts { public const string testQueue = @".\Private$\sample_queue"; } [JustInTimeActivation] [Transaction(TransactionOption.Required)] public class LceSubscriber : ServicedComponent, ILceMessage { public LceSubscriber() { } В качестве примера при обработке события подписчик проверяет наличие частной очереди сообщений и посылает в нее сообщение, после чего информирует координатор транзакций об успехе транзакции.

public void TriggerEvent(string message) { MessageQueue queue = MsmqTools.CreateQueue(Consts.testQueue); queue.Send(message, MessageQueueTransactionType.Automatic); ContextUtil.SetComplete(); } } class MainApp { public static void Main() { // Для ленивой регистрации приложения создается // служебная компонента LceSubscriber subscriber = new LceSubscriber(); // Создание постоянной подписки LceUtils.PermanentSubscription(Consts.comAppName, typeof(LceSubscriber).ToString(), EventsGuids.eventClassId, EventsGuids.interfaceId); } } // LceSubscriber.cs Make-файл для создания подписчика и издателя.

all: LceSubscriber.exe LcePublisher.exe LceSubscriber.snk: sn -k LceSubscriber.snk LcePublisher.snk: sn -k LcePublisher.snk LceSubscriber.exe: Seva*.cs LceEvents.cs LceSubscriber.cs LceSubscriber.snk csc /out:LceSubscriber.exe Seva*.cs LceEvents.cs LceSubscriber.cs /r:interop.comadmin.dll /keyfile:LceSubscriber.snk LcePublisher.exe: Seva*.cs LceEvents.cs LcePublisher.cs LcePublisher.snk csc /out:LcePublisher.exe Seva*.cs LceEvents.cs LcePublisher.cs /r:interop.comadmin.dll /keyfile:LcePublisher.snk

Содержание раздела