Шрифт:
Используя свойство 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, сервер получает доступ к учетным данным пользователя, от имени которого было запущено клиентское приложение, и может принимать решение о выполнении данного вызова.
По завершении вызова метода Add клиент получает из свойства контекста значение свойства serverName, добавленное в контекст вызова сервером при выполнении Add. В результате клиент получает информацию о сборке, содержащей код сервера, выполнившего вызов.
Результаты
Ниже приведен вывод на консоль сервера. Видно, что сервер получил информацию о том, что клиентское приложение было запущено Администратором.
Server is listening
UserName = Администратор
Bye
А вот и вывод на консоль клиента:
5 is sent to MyServer, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null
Total = 5
Bye
Возвращаемся к классу Workltem
Конструктор
Конструктор в качестве входных параметров принимает вызов в форме сообщения (reqMsg), ссылку на следующий перехватчик, которому будет переадресован данный вызов после того, как он отстоит всю очередь (nextSink) и ссылку на перехватчик для результатов асинхронного вызова (replySink). В случае синхронного вызова последний параметр задается равным null.