Thread.CurrentThread.GetHasheode() +
" IsPoolThread = " +
Thread.CurrentThread.IsThreadPoolThread +
" clientProcessId ="+ clientProcessId);
}
……
Необходимая модификация клиента (MуАрр. cs) представлена ниже
…….
using System.Diagnostics;
public class MyApp {
public static void Main() {
HttpChannel с = new HttpChannel();
ChannelServices.RegisterChannel(c);
Process p = Process.GetCurrentProcess();
try {
……
for (int i=0; i<100; i++) {
a. Add(5, p.Id);
}
…….
}
…….
Вот фрагмент вывода на консоль сервера из которого видно, что клиент никак не связан с рабочим потоком, выполняющим его вызов на сервере.
Account Add thread = 65 IsPoolThread = True clientProcessId =192
Tax notification: new Account operation: +5
Tax Notify thread = 65 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 65 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 65 IsPoolThread = True
Account Add thread = 65 IsPoolThread = True clientProcessId =192
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
Account Add thread = 3 IsPoolThread = True clientProcessId =165
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
…….
Еще стоит обратить внимание на то, что рабочий поток, выполняющий вызов метода Add компонента Account, выполняет и вызовы метода Notify для компонентов Tах и News, инициированные из компонента Account. Причина в том, что в рамках данного эксперимента все три компонента находятся в одном контексте синхронизации, и поток, вошедший в этот контекст, не выходит из него, пока не будут сделаны все вышеупомянутые вызовы. Только после этого другой поток может войти в данный контекст и начать выполнение метода Add.
Просмотрев файл LogFile, в который выполняется запись данных о перехваченных вызовах, можно заметить, что трассируются только вызовы к компоненту Account. Это объясняется тем, что именно компонент Account получает вызовы извне контекста (от клиентов), и эти вызовы перехватываются перехватчиком входящих вызовов атрибута трассировки. Вызовы, которые делаются к компонентам Tах и News, идут от компонентов Account и Tах и не пересекают границу контекста. Именно поэтому они и не перехватываются. Первые строки файла LogFile представлены ниже:
===SPbU.AOP_NET.Account, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
ctor
<<<IN>>> parameters: (
}
===SPbU.AOP_NET.Account, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
ctor
<<<OUT>>> parameters: {
}
===System.MarshalByRefObject, mscorlib, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089
InitializeLifetimeservice
<<<IN>>> parameters: (
}
===System.MarshalByRefObject, mscorlib, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089
InitializeLifetimeservice
<<<OUT>>> parameters: (
}
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<IN>>> parameters: {
sum= 5
'
clientProcessId= 192)
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<IN>>> parameters: {
sum= 5
'
clientProcessId= 165)
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<OUT>>> parameters: {
}
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<OUT>>> parameters: {
}
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<IN>>> parameters: {
sum= 5
'
clientProcessId= 192)
===clr: SPbU.AOP_NET.Account, MyServer
Add
<<<OUT>>> parameters: {
}
Компоненты размещаются в двух контекстах, но в одном домене синхронизации
Закомментируем атрибут Synchronization (), приписанный классу Account. Теперь, просматривая вывод на консоль сервера, можно заметить, что компонент Account размещается в контексте 1, а компоненты Tax и News в контексте 2:
Server is listening
News context = 2 News constructor thread = 9 IsPoolThread = True
Tax context = 2 Tax constructor thread = 9 IsPoolThread = True
Account context = 1 Account constructor thread = 9 IsPoolThread = True
…….
Просматривая файл LogFile видим, что теперь перехватываются вызовы к компонентам Tax и News, поступающие от компонента Account:
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
ctor
<<<IN>> parameters: {
}
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
ctor
<<<OUT>>> parameters: {
}
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
Notify
<<<IN>>> parameters: {
msg= new Account operation: +5)
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
Notify
}
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
get_news
<<<IN>>> parameters: {
}
===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
get_news
<<<OUT>>> parameters: {
}
===SPbU.AOP_NET.News, MyServer, Version=0.0.).0,
Culture=neutral, PublicKeyToken=null
Notify
<<<IN>>> parameters: {
msg= direct notification from Account)
===SPbU.AOP_NET.News, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
Notify
<<<OUT>>> parameters: {
}
В рамках данного эксперимента мы покажем, что оба контекста синхронизации размещаются в одном домене синхронизации. Для этого необходимо показать, что ссылка на свойство синхронизации во втором контексте указывает на свойство синхронизации первого контекста, т. е. оба контекста совместно используют одно свойство синхронизации (одну очередь работ и т. д.).
Внесем в код сервера следующие дополнения:
namespace SPbU.AOP_NET {
……
public class Account: ContextBoundObject, IAccumulator,
IAudit, IAccumulatorNew{
……
public Account() {
……
SynchronizationAttribute syncProperty =
(SynchronizationAttribute)
Thread.CurrentContext.GetProperty {
"Synchronization");
Console.WriteLine {
"Account syncProperty == Tax syncProperty "+
Object.ReferenceEquals(syncProperty, _tax.syncProperty));
}
……
}
……
public class Tax: ContextBoundObject {
……
private SynchronizationAttribute _syncProperty;
public Tax() {
…….
_syncProperty =
(SynchronizationAttribute)
Thread.CurrentContext.GetProperty {
"Synchronization");
……
}
…….
internal SynchronizationAttribute syncProperty {
get { return _syncProperty;}
}
……
}
…….
Просматривая консоль сервера убеждаемся, что ссылки на свойство синхронизации в обоих контекстах (в контексте, в котором живет компонент Account и в контексте, в котором живут компоненты Tax и News) указывают на один объект — свойство синхронизации домена синхронизации:
Server is listening
News context = 2 News constructor thread = 9 IsPoolThread = True
Tax context = 2 Tax constructor thread = 9 IsPoolThread = True
Account context = 1 Account constructor thread = 9 IsPoolThread = True
Account syncProperty == Tax syncProperty True
…….
Компоненты размещаются в трех контекстах и в двух доменах синхронизации
Заменим атрибут синхронизации, приписанный компоненту News следующей его версией:
[Synchronization(0x00000008)]
Задание данного атрибута означает, что компонент News будет располагаться в новом контексте (3), причем этот контекст образует и новый домен синхронизации. Компоненты Account и Tax должны располагаться в различных контекстах (1 и 2), но эти контексты должны входить в один домен синхронизации.