Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
public void Add(int sum) {
this.sum += sum;
MyCallContextUserName userName =
(MyCallContextUserName)CallContext.GetData("UserName");
Console.WriteLine("UserName = " +
userName.UserName);
CallContext.SetData("ServerName",
new MyCallContextServerName);
}
public int Total {
return this.sum;
}
}
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");
}
}
}
Относительно
В методе Add наш сервер будет не только получать очередной вклад и зачислять его на счет, но и работать с контекстом вызова.
Во-первых, предполагается, что клиент перед вызовом метода Add добавил в контекст вызова свойство с именем UserName. Соответствующее значение содержит учетные данные пользователя, от имени которого было запущено клиентское приложение. Значение свойства UserName задается ссылкой на экземпляр класса
[Serializable]
public class MyCallContextUserName:
ILogicalThreadAffinative {…}
Из определения этого класса видно, что его экземпляры могут передаваться в контексте вызова за пределы текущего контекста, т. к. этот класс определяется с атрибутом сериализации и наследует интерфейс ILogicalThreadAffinative.
Конструктор данного класса
public MyCallContextUserName {
_userName = Environment.UserName;
}
сохраняет в строковом поле _userName значение соответствующей переменной среды, получаемой как статическое свойство UserName класса Environment.
Используя свойство userName контекста вызова сервер в методе Add выясняет имя пользователя и выводит его на консоль:
MyCallContextUserName userName =
(MyCallContextUserName)CallContext.GetData("UserName");
Console.WriteLine("UserName = " +
userName.UserName);
Для доступа к нужному свойству используется статический метод GetData класса CallContext, которому в качестве параметра передается имя свойства. Полученное значение приводится к типу MyCallContextUserName.
Во-вторых, получив и выведя на консоль имя пользователя, сервер заканчивает выполнение метода Add, включая в контекст вызова свою информацию. Эту новую информацию сможет получить клиент, дождавшийся возврата из метода Add.
Итак, сервер добавляет в контекст вызова новое свойство с именем ServerName:
CallContext.SetData("ServerName",
new MyCallContextServerName};
Класс MyCallContextS erverName определяется аналогично классу MyCallContextUserName.
Основная функциональность этого класса определяется его конструктором:
public MyCallContextServerName {
_assembly = Assembly.GetExecutingAssembly;
_serverName = _assembly.FullName;
}
Здесь мы получаем ссылку на исполняемую сборку (т. е. на сборку сервера) и сохраняем в _serverName ее полное имя.
Остальная часть кода сервера не претерпела каких-либо изменений.
Клиент
using System; using MyServer;
using System. Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Net;
using System.Runtime.Remoting.Messaging;
public class MyApp {
public static void Main {
HttpChannel с = new HttpChannel;
ChannelServices.RegisterChannel(c);
try {
Account a = (Account)Activator.GetObject(typeof(Account),
"http://localhost:8080/Account",
WellKnownObjectMode.Singleton);
CallContext.SetData("UserName",
new MyCallContextUserName);
a. Add(5);
Console.WriteLine("5 is sent to " +
((MyCallContextServerName)CallContext.GetData(
"ServerName")).ServerName);
Console.WriteLine("Total = " +a.Total);
}
catch(WebException e) {
Console.WriteLine(e.Message);
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
finally!
Console.WriteLine("Bye");
}
}
}
Все отличие данного кода клиента от рассмотренных ранее примеров представлено в следующих строках
CallContext.SetData("UserName",
new MyCallContextUserName);
a. Add(5);
Console.WriteLine("5 is sent to " +
((MyCallContextServerName)CallContext.GetData (
"ServerName")).ServerName);
Перед вызовом метода Add клиент добавляет в контекст вызова уже рассмотренное свойство userName. В результате, при выполнении вызова Add, сервер получает доступ к учетным данным пользователя, от имени которого было запущено клиентское приложение, и может принимать решение о выполнении данного вызова.