Выбрать главу

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

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

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

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;

               }

        }

}

[Synchronization()]

[MyCallTrace("LogFile")]

public class News: ContextBoundObject {

        public News(){

                Console.WriteLine("News context = " +

                       Thread.CurrentContext.ContextID + "\n" +

                        "News constructor thread = " +

                        Thread.CurrentThread.GetHasheode() +

                       " IsPoolThread = " +

                       Thread.CurrentThread.IsThreadPoolThread);

          }

      public void Notify(String msg) {

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

                 Console.WriteLine("News Notify thread = " +

                        Thread.CurrentThread.GetHasheode() +

                        " IsPoolThread = " +

                        Thread.CurrentThread.IsThreadPoolThread);

          }

     }

public class AccountApp {

         public static void Main(){

               HttpChannel myChannel = new HttpChannel(8080);

               ChannelServices.RegisterChannel(myChannel);

               RemotingConfiguration.RegisterWellKnownServiceType (

                        typeof(Account), "Account",

                        WellKnownObjectMode.Singleton);

                Console.WriteLine("Server is listening");

                Console.ReadLine();

                Console.WriteLine("Bye");

           }

     }

}

Некоторые комментарии:

1. Определяемые в этом коде классы включаются в новое пространство имен — SPBU. AOP_NET. В этом же пространстве имен будет определен далее и атрибут трассировки вызовов MyCallTraceAttribute. При выборе имени пространства имен использовалась следующая рекомендация — префикс имени должен определять организацию, в которой работает разработчик. Попутно стоит заметить, что атрибут SynchronizationAttribute принадлежит пространству имен System.Runtime.Remoting.Contexts.

2. Классу Account наряду с атрибутом синхронизации (можно опустить часть "Attribute" при задании имени атрибута) приписан атрибут трассировки вызовов — [MyCallTrace ("LogFile")]. Здесь аргумент задает имя файла в рабочем каталоге, в конец которого будут записываться данные о вызовах методов этого класса. Однако трассировка вызовов будет обеспечиваться не всегда. Это касается только вызовов, сделанных извне контекста, в котором живет объект — экземпляр данного класса. Трассировка вызовов внутри данного контекста не производится. Понятие контекста и семантика данного атрибута будут рассмотрены далее.

3. Код класса Account претерпел некоторые изменения по сравнению с предыдущей главой:

♦ Появилось поле _tax — ссылка на экземпляр класса Tах. Новый экземпляр этого класса активируется в конструкторе класса Account с помощью оператора new. В результате при построении на стороне сервера экземпляра класса Account в этом же домене приложения формируется новый экземпляр класса Tах.

♦ В конструкторе класса Account выполняется вывод на консоль сервера идентификатора текущего контекста, т. е. контекста, в котором создается экземпляр класса Account. Кроме того на консоль выводится хеш потока, в котором выполняется конструктор, и логическое значение, равное true если этот поток выбран системой из пула потоков,

♦ При вызове метода Add происходит не только увеличение счета на величину нового вклада, но и вызывается метод Notify на объекте Tax, которому В качестве аргумента передается строка, сигнализирующая о поступлении нового вклада на счет.

Кроме того в этом же методе выполняется прямое уведомление компонента News. Для этого используется ссылка _tax.news на Экземпляр класса News, активированного к этому моменту экземпляром класса Tах. И здесь же на консоль выводится хеш потока, выполняющего метод Add, и информация о том, является ли этот поток потоком из пула потоков. Заметим, что хеш потока является уникальным в системе и может использоваться для идентификации потоков.