Опубликован: 11.05.2007 | Доступ: свободный | Студентов: 1706 / 243 | Оценка: 4.36 / 4.25 | Длительность: 16:06:00
Лекция 7:

Промежуточная среда COM+ и служба Enterprise Services

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

Для использования слабо связанных событий необходимо (рис. 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