ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
private List‹JamesBondCar› theJBCars = new List‹JamesBondCar›();
public CarProvider(JamesBondCar[] theCars) {
Console.WriteLine("Создание поставщика Car");
Console.WriteLine("с помощью пользовательского конструктора');
theJBCars.AddRange(theCars);
}
…
}
Чтобы позволить вызывающей стороне активизировать CarProvider с помощью нового конструктора, нужно построить приложение сервера, которое зарегистрирует CarProvider, как САО-тип, а не как WKO-тип. Это можно сделать программно с помощью метода, аналогичного RemotingConfiguration.RegisterActivatedServiceType(), или с помощью файла *.config на стороне сервера. Чтобы "жестко" задать имя CAO-объекта в программном коде сервера, передайте информацию типа или типов (после создания и регистрации канала), как предлагается ниже.
// "Жёсткое" указание того, что CarProvider является САО-типом.
RemotingConfiguration.RegisterActivatedServiceType(typeof(CAOCarGeneralAsm.CarProvider));
Если вы предпочтете использовать файл *.config, вместо элемента ‹wellknown› используйте элемент ‹activated›, как показано ниже.
‹configuration›
‹system.runtime.remoting›
‹application›
‹service›
‹activated type = "CAOCarGeneralAsm.CarProvider, CAOCarGeneralAsm"/›
‹/service›
‹channels›
‹channel ref="tcp" port="32496" /›
‹/channels›
‹/application›
‹/system.runtime.remoting›
‹/configuration›
Наконец, нужно обновить приложение клиента, и не только с целью учета соответствующего файла *.config (или программных изменений в базовом коде) для запроса доступа к удаленному САО-объекту, но и с тем, чтобы вызвать созданный пользовательский конструктор типа CarProvider. Вот как должен выглядеть модифицированный метод Main() на стороне клиента.
static void Main(string[] args) {
// Чтение обновленного файла *.config.
RemotingConfiguration.Configure("CAOCarProviderClient.exe.config");
// Создание массива типов для передачи поставщику.
JamesBondCar[] cars = {
new JamesBondCar ("Viper", 100, true, false),
new JamesBondCar("Shaken", 100, false, true),
new JamesВоndCar("Stirred", 100, true, true)
};
// Теперь вызов пользовательского конструктора.
CarProvider ср = new CarProvider(cars);
…
}
Обновленный файл *.сonfig клиента также должен использовать элемент ‹activated›, а не элемент ‹wellknown›. Кроме того, свойство url элемента ‹client› теперь должно указывать адрес зарегистрированного САО-объекта. Напомним, что при регистрации типа CarProvider сервером в виде WKO-объекта, клиент указывал соответствующую информацию в рамках элемента ‹wellknown›.
‹configuration›
‹system.runtime.remoting›
‹application›
‹client displayName = "CarClient" url = "tcp://localhost:32469"›
‹activated type="CAOCarGeneralAsm.CarProvider, CAOCarGeneralAsm" /›
‹/client›
‹channels›
‹channel ref="tcp"/›
‹/channels›
‹/application›
‹/system.runtime.remoting›
‹/configuration›
Чтобы "жестко" запрограммировать запрос САО-типа клиентом, можете использовать метод RegistrationServices.RegisterActivatedClientType(), как показано ниже.
static void Main(string[] args) {
// Использование "жестких" значений.
RemotingConfiguration.RegisterActivatedClientType(typeof(CAOCarGeneralAsm.CarProvider), "tcp://localhost:32469");
}
Запустив на выполнение обновленные компоновочные блоки сервера и клиента, вы с удовлетворением обнаружите, что можете передать свой пользовательский массив типов JamesBondCar удаленному объекту CarProvider через перегруженный конструктор.
Исходный код. Проекты CAOCarGeneralAsm, CAOCarProviderServer и CAOCarProviderCIient размещены в подкаталоге, соответствующем главе 18.
Схема лизингового управления циклом существования САО-типов и WKO-синглетов
Вы уже видели, что WKO-типы, сконфигурированные для активизации одиночного вызова, существуют только в процессе текущего вызова метода. Поэтому WKO-типы одиночного вызова являются объектами, не меняющими своего состояния в процессе выполнения. Как только текущий вызов завершается, WKO-тип одиночного вызова становится объектом, предназначенным для участия в очередной процедуре сборки мусора.
С другой стороны, САО-типы, а также WKO-типы, сконфигурированные для активизации в виде синглета, являются по своей природе объектами, кумулятивно изменяющими параметры своего состояния в процессе выполнения вызовов клиентов. Учитывая эти две доступные опции установки конфигурации, возникает следующий вопрос: как процесс сервера "узнает" о том, что пора уничтожить такой MBR-объект? Если сборщик мусора на сервере уничтожит MBR-объекты, находящиеся в использовании удаленным клиентом, это создаст проблемы, А если серверу придется ожидать освобождения MBR-типов слишком долго, это отрицательно повлияет на работу системы, особенно если соответствующие MBR-объекты удерживают важные ресурсы (связь с базой данных, неуправляемые типы или какие-то другие ресурсы).
Цикл существования MBR-объекта, являющегося CAO-типом или WKD-синглетом, контролируется по схеме лизингового управления, которая тесно связана с процессом сборки мусора .NET. Если "время аренды" MBR-объекта, являющегося CAO типом или WKO-синглетом истекает, объект становится кандидатом на участие в очередном цикле сборки мусора. Как и в случае любого другого .NET-типа, если удаленный объект переопределяет System.Object.Finalize() (с помощью синтаксиса деструктора C#), то среда выполнения .NET автоматически запустит соответствующую логику финализации.
Схема лизингового управления, используемая по умолчанию
Для MBR-объектов, являющихся САО-типами или WKO-синглетами, применяется так называемый лизинг по умолчанию, время которого равно пяти минутам. Если среда выполнения обнаружит, что MBR-объект, являющийся САО-типом или WKO-синглетом, остается неактивным в течение пяти минут, делается вывод о том, что клиент больше не использует данный удаленный объект, и поэтому этот объект может использоваться в процессе сборки мусора. При этом совсем не обязательно, чтобы после истечения времени лизинга объект помечался для сборки мусора немедленно. На самом деле есть много возможностей влиять на поведение, задаваемое лизингом по умолчанию.
Например, при каждом вызове клиентом члена удаленного MBR-обьекта, являющегося САО-типом или WKO-синглетом, время лизинга снова устанавливается равным пяти минутам. Но кроме автоматического обновления интервала времени лизинга при вызове клиента, среда выполнения .NET обеспечивает три дополнительные альтернативы.
• Установки лизинга по умолчанию для удаленных объектов могут переопределяться файлами *.config.
• Могут использоваться спонсоры лизинговой схемы сервера, действующие от имени удаленного объекта, время лизинга которого уже истекло.
• Могут использоваться спонсоры лизинговой схемы клиента, действующие от имени удаленного объекта, время лизинга которого уже истекло.
Мы рассмотрим каждую из указанных возможностей в следующих разделах, а пока что давайте рассмотрим установки лизинга, принятые для удаленного типа по умолчанию. Вспомните, что базовый класс MarshalByRefObject определяет член с именем GetLifetimeService(). Этот метод возвращает ссылку на внутренний объект, поддерживающий интерфейс System.Runtime.Remoting.Lifetime.ILease. Интерфейс ILease можно использовать для управления параметрами лизинга данного САО-типа или WKO-синглета. Вот формальное определение этого интерфейса.
public interface ILease {
TimeSpan CurrentLeaseTime { get; }
LeaseState CurrentState { get; }
TimeSpan InitialLeaseTime { get; set; }
TimeSpan RenewOnCallTime { get; set; }
TimeSpan SponsorshipTimeout { get; set; }
void Register(System.Runtime.Remoting.Lifetime.ISponsor obj);
void Register(System.Runtime.Remoting.Lifetime.ISponsor obj, TimeSpan renewalTime);
TimeSpan Renew(TimeSpan renewalTime);
void Unregister(System.Runtime.Remoting.Lifetime.ISponsor obj);
}
Интерфейс ILease не только позволяет получить информацию о текущих параметрах лизинга (с помощью CurrentLeaseTime, CurrentState и InitialLeaseTime), но и обеспечивает возможность построения "спонсоров" лизинга (более подробно об этом будет говориться позже). Роль каждого из членов ILease описана в табл. 18.6.
Таблица 18.6. Члены интерфейса ILease
Член Описание CurrentLeaseTime Читает информацию о времени, оставшемся до отключения данного объекта при отсутствии новых вызовов методов объекта CurrentState Читает информацию о текущем состоянии лизинга, представленную значением перечня LeaseState InitialLeaseTime Читает или устанавливает исходное время лизинга. Исходное время лизинга – это время от начала активизации объекта до истечения лизинга при отсутствии новых вызовов методов объекта RenewOnCallTime Читает или устанавливает значение времени, на которое вызов удаленного объекта увеличивает значение CurrentLeaseTime SponsorshipTimeout Читает или устанавливает значение времени ожидания спонсора для возвращения времени возобновления лизинга Register() Перегруженный метод, регистрирующий спонсора данного лизинга Renew() Возобновляет лизинг с указанным временем Unregister() Удаляет указанный спонсор из списка спонсоровДля иллюстрации особенностей лизинга по умолчанию для удаленных СAО-типов и WKO-синглетов определим в нашем текущем проекте CAOCarGeneralAsm новый внутренний класс LeaseInfo. Статический член LeaseStats() этого класса выводит информацию о текущем лизинге для типа CarProvider в окно консоли сервера (не забудьте указать директиву using для пространства имен System.Runtime.Remoting.Lifetime, чтобы сообщить компилятору о месте нахождения определении типа ILease).