COM+ и .NET – практический подход – часть 3 - Как уведомить ASP.NET из серверного приложения COM+

ОГЛАВЛЕНИЕ

Как уведомить ASP.NET из серверного приложения COM+

Регистрация класса в качестве серверного приложения COM+ повышает устойчивость и доступность приложения, но имеет недостатки. Один недостаток – необходимость использовать дистанционную связь между компонентом COM+ и вызывающим приложением. Если вызывается компонент COM+ -  дистанционная связь осуществляется CLR, но если надо вызвать приложение из приложения COM+, для ее обеспечения придется сделать некоторую работу.

Один из распространенных сценариев – события обратного вызова из приложения COM+ к вызывающему приложению. Когда приложению COM+ надо вызвать приложение, приложение превращается в сервер дистанционной связи. Чтобы приложение служило сервером дистанционной связи, ему надо назначить порт TCP.

Пора посмотреть, как реальная задача решается с помощью серверных приложений COM+ и событий обратного вызова. Допустим, надо прочитать из базы данных очень большой объем данных, обработать эти данные и отобразить все данные пользователю. При стандартной схеме обработки страницы извлекаются все данные, форматируются и отправляются клиенту в одном буфере. Конечный пользователь получит очень медленное приложение. При работе с большим объемом данных лучше прочитать кусок от всех данных, отформатировать его и отправить непосредственно пользователю. Применение такой схемы дает ощущение использования хорошо работающей системы. Пользователь быстро видит какие-то данные, и по мере увеличения времени он видит все больше данных, пока не отправятся все данные.

Для обеспечения такой последовательности обработки страницы необходимо: а) установить буферизацию в ложь, чтобы можно было отправлять куски данных; б) прочитать данные из базы данных с помощью DataReader, собрать кусок записей, отформатировать его и отправить клиенту. Для повышения устойчивости приложения лучше поместить чтение данных в класс, регистрирующийся как приложение COM+. Чтобы компоненты COM+ могли отправлять куски данных приложению, реализуются события обратного вызова, уведомляющие вызывающую программу, когда кусок данных готов к форматированию и отправке.

Пробный проект состоит из нового веб-приложения (ASPNET_COMPLUSE_CALLBACK), обычной сборки (ComPlusFacade) и класса серверного приложения COM+ (ComPlusLib). Задача ComPlusFacade – получить события компонента COM+ и записать полученные данные в выходной буфер. ComPlusFacade является отдельной сборкой, потому что и вызывающее приложение, и вызываемый компонент COM+ должны быть в GAC(глобальный кэш сборок), чтобы позволить абсолютно всем им использовать другого. Перед запуском примера не забудьте зарегистрировать эти сборки в GAC.

ComPlusLib содержит два класса: XMLArg, декорированный атрибутом Serializable, чтобы обеспечить передачу аргумента события по каналу дистанционной связи.


   [Serializable()]
   public class XMLArg : EventArgs
   {
      string XMLBuffer;
      public XMLArg()
      {
      }
      public XMLArg(string XMLBufferArg)
      {
         this.XMLBuffer = XMLBufferArg;
      }
      public string XMLBufferArg
      {
         get
         {
            return this.XMLBuffer;
         }
         set
         {
            this.XMLBuffer = value;
         }
      }
      public override string ToString()
      {
         return this.XMLBuffer;
      }
   }

clsComPlusLib является типичным компонентом COM+, содержащим объявленное событие, запускающим каждый сквозной оператор цикла for внутри метода ProcessData.

   [ProgId("clsComPlusLib"),
   Transaction(TransactionOption.NotSupported),
   MustRunInClientContextAttribute(false),
   EventTrackingEnabledAttribute(true),
   JustInTimeActivation(true),
   Synchronization(SynchronizationOption.Required),
   Serializable
   ]
   public class clsComPlusLib : ServicedComponent
   {
      public new event EventHandler DataArrive;
      public clsComPlusLib()
      {
      }
      public void ProcessData()
      {
      for (int i=0 ; i<100000 ; i++)
      {
         EventArgs XML = new XMLArg ("i=" + i + "<br>\n");
         this.DataArrive(null,XML);
      }
   }
}

CLR зарегистрирует ComPlusLib в COM+. Вы должны зарегистрировать ComPlusLib в GAC посредством перетаскивания или gacutil.exe.

ComPlusFacade – интересная часть примера. ComPlusFacade является связующим звеном между веб-приложением и серверным приложением COM+. FacadeObjByRef также декорирован сериализацией для обеспечения передачи класса через дистанционную связь. Чтобы FacadeObjByRef мог служить сервером дистанционной связи, он унаследован от MarshalByRefObject, и объявлен член типа TcpChannel.

[Serializable()]
public class FacadeObjByRef : MarshalByRefObject
{
   protected ComPlusLib.clsComPlusLib eventHandler =
new ComPlusLib.clsComPlusLib();
   protected System.IO.Stream outStream;
   public static TcpChannel theChannel;

Подрядчик класса получает поток в качестве параметра. Поток отправки должен быть потоком вывода ответа страницы, используемым для выдачи полученных данных клиенту. Внутри конструктора регистрируется TcpChannel, чтобы позволить среде выполнения дистанционной связи выбрать свободный порт и установить обработчик события для события компонента COM+.

   public FacadeObjByRef(System.IO.Stream outStream) 
   {
      lock(this)
      {
         if (theChannel == null)
         {
            theChannel = new TcpChannel(0);
            ChannelServices.RegisterChannel(theChannel);
         }
      }
      if (textEncoder == null)
      {
         textEncoder = Encoding.UTF8;
      }
      this.outStream = outStream;
      this.eventHandler.DataArrive += new
System.EventHandler(this.DataArive);
   }

ProcessData является открытым методом класса, вызываемым веб-страницей и вызывающим приложение COM+ синхронно, чтобы запустить его работу.

public void proccessData()
{
   eventHandler.ProcessData();
   this.CloseStream();
   this.cleanUp();
}

Пока приложение COM+ делает свою работу, событие возбуждается и обрабатывается DataArrive. DataArrive преобразует аргумент события в массив байтов и отправляет этот массив байтов клиенту с помощью внутреннего члена, хранящего буфер потока ответа вызывающей страницы.

public void DataArive(object sender, System.EventArgs e)
{
   byte[] toWrite = textEncoder.
GetBytes(((ComPlusLib.XMLArg)e).XMLBufferArg + "\n");
   outStream.Write(toWrite, 0, toWrite.Length);
}

ComPlusFacade выполняется в процессе веб-приложения, надо только зарегистрировать его в GAC.

Веб-приложение ASPNET_COMPLUSE_CALLBACK имеет одну страницу aspx (webform1.aspx), отключающую стандартную буферизацию и создающую объект из класса FacadeObjByRef и вызывающую метод ProcessData.

private void Page_Load(object sender, System.EventArgs e)
{
   Response.BufferOutput = false;
   ComPlusFacade.FacadeObjByRef oObj = new
ComPlusFacade.FacadeObjByRef (Response.OutputStream );
   oObj.proccessData ();
}

Осталось запустить ASPNET_COMPLUSE_CALLBACK и посмотреть на его поведение. Страница быстро показывает куски данных, продолжающие приходить, и присоединяет их к HTML в браузере.

Заключение

Цель статьи – показать, как использовать службы COM+ для решения типичных задач программирования при разработке веб-приложений. Начинается с изучения влияния приложения сервера и библиотеки COM+ на производительность и недостатков использования серверного приложения.

После рассмотрения влияния на производительность объясняется и показывается, насколько огромен вклад использования серверного приложения COM+ в устойчивость, надежность приложений и контроль над ними. Решение повседневных задач, таких как инициализация длинного компонента, задача длинных компонентов, уведомление и другие, показывает, как использование служб COM+ и особенно серверных служб COM+ сокращает написание кода и усилия программистов.

COM+ предоставляет мощные службы, помогающие быстро создать развитое и устойчивое приложение. Основной недостаток использования служб COM+ - снижение производительности. Можно использовать часть служб COM+ с помощью служб без компонентов без снижения производительности и приложения библиотеки COM+ с приемлемым снижением. Сервер COM+, предоставляющий наиболее интересные службы, плохо влияет на производительность преимущественно из-за использования DCOM (распределённая компонентная модель объектов).

Перед использованием служб COM+ следует создать пробное приложение и протестировать его с ACT, чтобы выяснить, соответствует ли использование сервера COM+ целевой производительности приложения. Будем  надеяться, следующие версии windows, такие как лонгхорн, будут поставляться со службами COM+, не основанными на DCOM, что позволит большему числу приложений использовать серверное приложение COM+.