Добавить в цитаты Настройки чтения

Страница 214 из 372

Несмотря на определенные различия между CLR из .NET и SSCLI, код из CLI является полезным источником информации при изучении .NET. В частности, изучение кода атрибута SynchronizationAttribute из SSCLI позволяет глубже понять его семантику, что необходимо для правильного и эффективного использования данного атрибута в .NET.

В последующих разделах данной главы технология работы с контекстами и пользовательскими атрибутами будет продемонстрирована на простом примере, который является некоторым расширением ранее рассмотренного примера из предыдущей главы.

Описание примера

Изучаемый ниже пример разрабатывался с целью демонстрации ряда тонких моментов, связанных с контекстами, потоками и пользовательскими атрибутами. На основе использования этого примера мы проведем серию экспериментов, которые помогут прояснить излагаемые вопросы.

Как и в предыдущем разделе консольное клиентское приложение делает вклад на счет, поддерживаемый другим ранее запущенным консольным серверным приложением. Серверное приложение содержит три компонента, представляемые классами Account, Tax и News.

Компонент Account поддерживает счет, позволяя клиентам сделать вклад (метод Add) и узнать величину текущего счета (метод Total).

Компоненты Tax и News представляют соответственно налоговую службу и агентство новостей. Оба компонента получают уведомления о вкладах на счет (метод Notify) и выводят соответствующую информацию на консоль.

Компонент Tах активируется компонентом Account, который добровольно информирует Tax о каждом сделанном вкладе в процессе выполнения вызова метода Add. В свою очередь компонент Tах активирует компонент News, которому и передает полученную от Account информацию для придания ее гласности. Не полагаясь исключительно на компонент Tах, компонент Account получает от Tах ссылку на компонент News и самостоятельно напрямую посылает уведомление этому компоненту.

Для демонстрации пользовательских атрибутов, позволяющих задавать набор сервисов, доступных компонентам серверного приложения, мы будем использовать два атрибута:

• SynchronizationAttribute

Этот атрибут синхронизации реализован в .NET и уже применялся в примере предыдущей главы. Как уже отмечалось выше, семантика этого атрибута весьма не проста, и для ее полного понимания полезно познакомиться с кодом этого атрибута, представленным в SSCLI (файл sscli clr scr bcl system runtime remoting synchronizeddispatch.es). Этот код содержит 1010 строк (вместе с комментариями). Мы не будем здесь его разбирать полностью, однако основные сведения, полученные при его изучении, будут в данной главе изложены и продемонстрированы в экспериментах.

• MyCallTraceAttribute

Код этого атрибута трассировки вызовов приводится в данной главе. Надо заметить, что атрибуты с семантикой трассировки вызовов очень популярны среди авторов, пишущих на темы .NET. Приведенный здесь код содержит фрагменты из ряда опубликованных примеров (в частности, из кода к статье [АОРЗ]) и используется исключительно в демонстрационных целях.

Весь код примера содержится в трех файлах:

• MyApp.cs

Этот файл содержит код консольного клиентского приложения.

• MyServer.cs

Файл содержит код консольного серверного приложения и трех компонентов (Account, Tax, News).

• MyCallTrace.cs

Этот файл содержит код атрибута трассировки вызовов.

Ниже приводится makefile, который можно использовать для компиляции и сборки клиентского и серверного приложений

all: МуАрр MyServer

clean:

      @del МуАрр. exe MyServer.exe

МуАрр: МуАрр. ехе

МуАрр. exe: MyApp.cs MyServer.exe

      csc /r: MyServer.exe MyApp.cs

MyServer: MyServer.exe

MyServer.exe: MyServer.cs MyCallTrace.cs

       csc MyServer.cs MyCallTrace.cs

Из этого кода видно, что и клиентское, и серверное приложение являются приложениями типа .ехе и запускаются в различных доменах приложений. Для использования этого makefile достаточно запустить nmake, в результате чего будут получены файлы МуАрр. ехе и MyServer.ехе.

Серверное приложение

Ниже приводится код из файла MyServer.cs, который является некоторым расширением одноименного файла, рассмотренного в предыдущей главе.

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Cha

using System.Runtime.Remoting.Cha

using System.Threading;

using System.Runtime.Remoting.Contexts;

namespace SPbU.AOP_NET {

public interface IAccumulator {

      void Add(int sum);

}

public interface IAudit {

      int Total();

}

[Synchronization()]

[MyCallTrace("LogFile")]

public class Account: ContextBoundObject,

       IAccumulator, IAudit {





       private Tax _tax;

       private int _sum = 0;

        public Account() {

            _tax = new Tax ();

            Console.WriteLine("Account context = " +

                Thread.CurrentContext.ContextID + "n" +

                "Account constructor thread = " +

                Thread.CurrentThread.GetHasheode() +

                " IsPoolThread = " +

                        Thread.CurrentThread.IsThreadPoolThread);

        }

        public void Add(int sum) {

                _sum += sum;

                _tax.Notify("new Account operation: +" + sum); _

                _tax.news.Notify("direct notification from Account");

               Console.WriteLine("Account Add thread = " +

                     Thread.CurrentThread.GetHasheode() +

                    " IsPoolThread = " +

                    Thread.CurrentThread.IsThreadPoolThread);

         }

         public int Total() {

                 return _sum;

         }

}

[Synchronization()]

[MyCallTrace("LogFile")]

public class Tax: ContextBoundObject {

           private News _news;

           public Tax() {

                  _news = new News();

                 Console.WriteLine("Tax context = " +

                      Thread.CurrentContext.ContextID + "n" +

                       "Tax constructor thread = " +

                      Thread.CurrentThread.GetHasheode() +

                      " IsPoolThread = " +

                      Thread.CurrentThread.IsThreadPoolThread);

          }

          public void Notify(String msg) {

                Console.WriteLine("Tax notification: " + msg);

                Console.WriteLine("Tax Notify thread = " +

                       Thread.CurrentThread.GetHasheode() +

                        " IsPoolThread = " +

                        Thread.CurrentThread.IsThreadPoolThread);

               _news.Notify(msg);

           }

           public News news {

               get {

                     return _news;