Промежуточная среда COM+ и служба Enterprise Services
Использование слабо связанных событий
Для использования слабо связанных событий необходимо (рис. 6.7):
- создать интерфейс, описывающий методы события;
- создать так называемый класс события ( event class ), который является особой обслуживаемой компонентой, реализующей указанный интерфейс;
- создать реализующую этот же интерфейс обслуживаемую компоненту и подписать ее на событие; таких сервисных компонент можно создать несколько и они могут входить в состав различных приложений COM+;
- написать в издателе код создания события, заключающийся в создании экземпляра класса события и вызова его методов.
Сначала создается интерфейс, описывающий один или несколько методов событий. Поскольку для подписки на событие необходимо будет использовать идентификаторы класса события и интерфейса, то они описаны как константы.
// 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.csMake-файл для создания подписчика и издателя.
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
