Серверное приложение
Ниже приводится код из файла 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, и информация о том, является ли этот поток потоком из пула потоков. Заметим, что хеш потока является уникальным в системе и может использоваться для идентификации потоков.