Рассмотрим три доступных для использования приемника сообщения.
Уполномоченный приемник
Можно получить цепочку уполномоченных приемников с помощью интерфейса
IEnvoyInfo
. Маршализованная объектная ссылка
ObjRef
имеет свойство
EnvoyInfo
, которое возвращает интерфейс
IEnvoyInfo
. Список уполномоченных приемников создается из серверного контекста, поэтому сервер может добавлять функциональность клиенту. Уполномоченные приемники собирают информацию об идентичности клиента и предают ее серверу.
Приемник серверного контекста
Когда
сообщение получено на серверной стороне канала, оно передается приемникам серверного контекста. Последний из этих приемников направляет сообщение в цепочку объектных приемников.
Объектный приемник
Объектный приемник ассоциируется с определенным объектом. Если объектный класс определяет атрибуты определенного контекста, то для объекта создаются приемники контекста.
Передача объектов в удаленные методы
Типы параметров для вызовов удаленных методов не ограничены только базовыми типами данных, но могут также быть классами, которые определяет программист. Для удаленных методов различают три типа классов:
□ Классы, маршализуемые по значению, обычно сериализуются через канал. Классы, которые должны быть маршализованы, либо реализуют интерфейс
ISerializable
, либо помечаются с помощью атрибута
[Serializable]
. Объекты этих классов не имеют удаленной идентичности, так как весь объект маршализуется через канал, а объект, который сериализуется клиенту, является независимым от серверного объекта (или наоборот). Классы, маршализуемые по значению, называются также несвязанными классами, так как они не имеют данных, которые зависят от домена приложения.
□ Классы, маршализуемые по ссылке, имеют удаленную идентичность. Объекты не передаются по линиям связи, а вместо этого возвращается прокси. Класс, который маршализуется по ссылке, должен выводиться из
MarshalByRefObject
. Объекты
MarshalByRefObject
называют объектами, связанными с доменом приложения. Специализированной версией
MarshalByRefObject
является класс
ContextBoundObject
: абстрактный класс
ContextBoundObject
выводится из
MarshalByRefObject
. Если класс выводится из
ContextBoundObject
, требуется прокси даже в том же самом домене приложения, когда пересекаются границы контекстов.
□ Классы, которые не являются сериализуемыми и не выводятся из
MarshalByRefObject
, не могут использоваться в параметрах открытых методов удаленных объектов. Эти классы связаны с доменом приложения, где они созданы. Такие классы должны использоваться, если класс имеет члены данных, допустимые только в домене приложения, такие как дескриптор файла Win32.
Чтобы увидеть маршализацию в действии, изменим удаленный объект для пересылки двух объектов клиенту: пусть класс
MySerialized
посылает маршализацию по значению, а класс
MyRemote
маршализует по ссылке. В методах сообщение записывается на консоль, чтобы можно было проверять, сделан ли вызов на клиенте или на сервере. Кроме того, класс Hello изменяется, чтобы возвращать экземпляры
MySerilized
и
MyRemote
:
using System;
namespace Wrox.ProfessionalCSharp {
[Serilizable]
public сlass MySerilized {
public MySerilized(int val) {
a = val;
}
public void Foo {
Console.WriteLine("MySerialized.Foo called");
}
public int A {
get {
Console.WriteLine("MySerialized A called");
return a;
}
set {
a = value;
}
}
protected int a;
}
public class MyRemote : System.MarshalByRefObject {
public MyRemote(int val) {
a = val;
}
public void Foo {
Console.WriteLine("MyRemote.Foo called");
}
public int A {
get
Сonsole.WriteLine("MyRemote.A called");
return a;
}
set {
a = value;
}
}
protected int a;
}
/// <summary>
/// Краткое описание Class1
/// </summary>
public class Hello : System.MarshalByRefObject {
public Hello {
Console.WriteLine("Constructor called");
}
~Hello {
Console.WriteLine("Destructor called");
}
public string Greeting(string name) {
Console.WriteLine("Greeting called");
return "Hello, " + name;
}
public MySerialized GetMySerilized {
return new MySerialized(4711);
}
public MyRemote GetMyRemote {
return new MyRemote(4712);
}
}
}
Клиентское приложение также необходимо изменить, чтобы увидеть результаты при использовании маршализации объектов по значению и по ссылке. Мы вызываем методы
GetMySerialized
и
GetMyRemote
, чтобы получить новые объекты и проверить, не используется ли прозрачный прокси.
ChannelServices.RegisterChannel(new TcpChannel);
Hello obj =
(Hello)Activator.GetObject(typeof(Hello),
"tcp://localhost:8086/Hi");
if (obj == null) {
Console.WriteLine("could not locate server");
return;
}
MySerialized ser = obj.GetMySerialized;
if (!RemotingServices.IsTransparentProxy(ser)) {
Console.WriteLine("ser is not a transparent proxy");