Почему у моего объекта удаленного взаимодействия C # истекает время ожидания, даже если время жизни возвращает null?

#c# #.net #events #windows-services #remoting

#c# #.net #Мероприятия #windows-services #удаленное взаимодействие

Вопрос:

это последнее средство после многих дней поиска в Google в попытке найти окончательный ответ на мой вопрос.

Я создал службу Windows, форму Windows и объект удаленного взаимодействия (все на C #). Я использую объект удаленного взаимодействия для связи между сервисом и формой, используя события.

Вот упрощенный пример типичного взаимодействия между объектами:

  • AdminForm вызывает метод RemoteObject RequestLoadForm()
  • RemoteObject запускает событие, которое прослушивает AdminService
  • AdminService получает уведомление об этом событии и вызывает LoadFormData (строковые данные) для RemoteObject
  • RemoteObject запускает событие, которое прослушивает AdminForm
  • AdminForm получает уведомление о событии и может использовать строковые данные для установки значений в элементах управления AdminForm

Все это работает нормально, все прекрасно взаимодействует в течение первых 5 минут или около того. После этого соединение между объектами каким-то образом разрывается, и я больше не могу обмениваться данными между объектами.

Первая попытка устранения проблемы заключалась в перезаписи метода InitializeLifetimeService для возврата null. Это не помогло (хотя это может избежать любых будущих проблем с арендой).

Вторая попытка заключалась в том, чтобы сделать мои AdminForm и AdminService спонсорами RemoteObject и настроить их на продление аренды объекта. Еще раз, проблема не устранена.

В моих различных поисковых системах я нашел, что кто-то упоминал что-то о том, что обработчики событий собирают мусор. Я не уверен, проблема в этом или нет, но я подумал, что стоит упомянуть об этом.

Это ошибка, которая появляется после того, как соединение простаивало более 5 минут:

System.Runtime.Удаленное взаимодействие.Исключение RemotingException не было обработано пользовательским кодом
Message =»Запрошенная служба не найдена»
Source =»System.Runtime.Удаленное взаимодействие»

Самое странное в этом то, что это происходит на стороне AdminService. AdminForm вызывает метод для RemoteObject нормально. Это приводит к появлению события, а затем AdminService видит это событие и пытается вызвать метод LoadFormData RemoteObject (строковые данные), и именно здесь генерируется исключение.

Я полностью исчерпан поисками в Google, поскольку, похоже, не могу найти то, что мне нужно, чтобы это исправить.

Комментарии:

1. Можете ли вы опубликовать какой-нибудь код соответствующих классов?

2. Какой протокол вы используете для связи? У меня была та же проблема с использованием канала IPC — базовый канал был бы закрыт ОС, если бы данные не отправлялись в течение примерно 5 минут.

3. Просто чтобы убедиться, что вы знаете: удаленное взаимодействие .NET устарело в пользу WCF. Возможно, именно поэтому вы не получаете много ответов.

4. Устарело? Требуется цитирование. WCF чрезвычайно тяжеловесен, не все хотят его использовать. В частности, удаленное взаимодействие является наиболее разумным способом обмена данными между двумя доменами приложений в одном процессе. И «шестиминутный тайм-аут» является огромной проблемой. Тем более, что отладка ужасна (приходится ждать 6 минут, чтобы узнать, сработала ли ваша настройка!)

Ответ №1:

Я сталкиваюсь с довольно похожей проблемой. Надеюсь, что следующее наблюдение и решение подойдут для всех, у кого тоже есть подобная проблема.

Объект A обменивается данными с объектом B через домен приложения, в то время как объект B будет перезванивать объекту A через некоторые обработчики событий. Оба объекта A и B наследуются от MarshalByRefObject, чтобы разрешить взаимный вызов в домене приложения.

Объект B переопределяет InitializeLifeTimeService, чтобы возвращать null для бесконечной аренды. Однако срок действия соединения все равно истечет примерно через 5 минут (начальное время аренды удаленного доступа по умолчанию) после запуска программы.

Важным замечанием является то, что вызов из объекта A все равно будет выполнен успешно, но когда объект B перезванивает, исключением является вызов объекта B. По-видимому, истечение срока действия соединения произошло для прокси обратного вызова объекта A, а не наоборот, как мы думали.

Следовательно, быстрый ответ, убедитесь, что оба объекта A и B переопределяют InitializeLifeTimeService для возврата null. Это решит проблему, по крайней мере, в моем случае.

Просто некоторые дополнительные элементы, когда срок действия соединения истек, это необязательно означает, что подключенный объект является собранным мусором. Истечение срока аренды приведет к отключению прокси, но фактический объект все еще может присутствовать в соответствующем домене приложения. Если вы сохраняете равное истечению срока аренды с объектом, являющимся GC’d, то это может ослепить вас от просмотра всей картины.

Ответ №2:

должно быть переопределено:

 public override object InitializeLifetimeService(){
  return null;
}
  

Ответ №3:

Вы могли бы установить статические свойства в System.Runtime.Удаленное взаимодействие.Время жизни.Службы времени жизни на стороне сервера:

 System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseTime = TimeSpan.MaxValue;
  

но я предпочитаю использовать договоры аренды / спонсорства (на стороне клиента)

http://msdn.microsoft.com/en-us/library/6tkeax11.aspx

 MarshalByRefObject obj = remotingObject as MarshalByRefObject;
ILease lease = (ILease)obj.GetLifetimeService();
MyClientSponsor sponsor = new MySponsor();
lease.Register(sponsor);
  

если у вас возникли какие-либо другие проблемы с сортировкой, используйте System.Runtime.Удаленное взаимодействие.Услуги.Пространство имен TrackingServices
http://msdn.microsoft.com/en-us/library/system.runtime.remoting.services.trackingservices.aspx

Комментарии:

1. Для System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseTime этой ссылки msdn.microsoft.com/en-us/magazine/cc300474.aspx говорится «Обратите внимание, что вы должны установить глобальные значения по умолчанию для аренды, прежде чем регистрировать типы для удаленного доступа (программно или с использованием файла конфигурации), потому что сразу после регистрации хост может начать обслуживать удаленные вызовы, и эти вызовы не будут использовать новые значения по умолчанию.». Однако у меня все еще возникают проблемы с COM-объектами, для которых я не могу изменить аренду.

Ответ №4:

Вы должны перезаписать метод InitializeLifeTimeService(), а не GetLifetimeService(), чтобы вернуть null.

  public object InitializeLifetimeService(){
   return null;
 }
  

Тогда у объекта remove должно быть бесконечное время жизни.

Комментарии:

1. с дополнительным бесконечным использованием памяти это может быть плохо в зависимости от контекста

Ответ №5:

На это может быть несколько причин.

  • Возможно, вы переопределяете InitializeLifetimeService не тот объект. Найдите в своем исходном коде все упоминания MarshalByRef и внимательно изучите каждое из них.

  • Бесконечная аренда длится только до тех пор, пока домен приложения не будет выгружен. Найдите в своем исходном коде все упоминания Unload и внимательно изучите каждое из них, которое выгружает какой-либо домен приложения.

  • Домен приложения мог быть перезагружен при завершении процесса, например, при перезапуске службы Win32. Он также может быть выгружен сторонним кодом, если ваш сервер развернут на каком-либо сервере приложений и какая-либо операция развертывания или восстановление после ошибок запускает перезагрузку; изучите сторонние журналы, чтобы найти доказательства этого.

  • Добавьте достаточно протоколирования и тщательно изучите трассировки стека исключений, чтобы быть полностью уверенным, что вы не вызываете серверный объект третьей стороны (возможно, через ваш собственный объект сервера бесконечной аренды) или более старую версию вашего собственного кода, загруженную неизвестно откуда, так что исследование исходного кода, приведенное выше, могло пропустить это.

Я только что закончил исследование инцидента, который оказался комбинацией первого и последнего элемента в моем списке.