Исключение «Объект отключен или не существует на сервере» - PullRequest
41 голосов
/ 14 июня 2011

Мне нужно использовать кросс-доменные вызовы в моем приложении, и иногда у меня возникает это исключение RemotingException:

Object '/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem' не отключен илисервер.

Целевой объект все еще жив, я проверил его.

UPD Я установил точку останова в финализаторе целевого объекта, и он никогда не попадет.Таким образом, этот объект жив и не был собран GC.

Ответы [ 7 ]

33 голосов
/ 14 июня 2011

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

Обновление : К сожалению, выпуски MSDN Magazine, выпущенные в 2008 году или старше, больше не доступны для просмотра в Интернете, а доступны только в виде файлов CHM, которые необходимо загрузить на локальный компьютер. Предыдущие выпуски можно найти в:

15 голосов
/ 22 сентября 2011

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

2 голосов
/ 29 марта 2018

У меня была такая же проблема, и я искал много часов с помощью множества сообщений StackOverflow.

Я наконец-то нашел полную проблему.

  1. Я должен использовать Спонсора, чтобы поддержать мой MarshalByRefObject.
  2. У меня тогда была та же проблема, что и у @ user626528: объект жив, но у меня было исключение. Фактически, Мне нужно было "спонсировать" ВСЕ " TransparentProxy " экземпляров , а не только главный: мой главный объект, созданный в SandBox (другой домен приложения), возвращает ссылки на другие MarshalByRefObjects .

Вот полное объяснение и пример использования:

Мой класс "Loader" наследуется от MarshalByRefObject, и я поддерживаю его классом ISponsor. Я знаю, что «ClientSponsor» существует в .NET, но у меня не было возможности определить, когда и когда вызывается Renewal (), поэтому я сделал свой класс с помощью сообщества StackOverflow (см. Комментарии к коду):

/// <see cref="https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called"/>
public class RemotingSponsor : MarshalByRefObject, ISponsor, IDisposable
{
    /*
     * @CoryNelson said :
     * I've since determined that the ILease objects of my sponsors 
     * themselves are being GCed. They start out with the default 5min lease 
     * time, which explains how often my sponsors are being called. When I 
     * set my InitialLeaseTime to 1min, the ILease objects are continually        
     * renewed due to their RenewOnCallTime being the default of 2min.
     * 
     */ 

    ILease _lease;

    public RemotingSponsor(MarshalByRefObject mbro)
    {
        _lease = (ILease)RemotingServices.GetLifetimeService(mbro);
        if (_lease == null) throw new NotSupportedException("Lease instance for MarshalByRefObject is NULL");
        _lease.Register(this);
    }

    public TimeSpan Renewal(ILease lease)
    {
        Debug.WriteLine("RemotingSponsor.Renewal called");
        return this._lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;
    }


    public void Dispose()
    {
        if (_lease != null)
        {
            _lease.Unregister(this);
            _lease = null;
        }
    }

    public override object InitializeLifetimeService()
    {
        /*
         *
         * @MatthewLee said:
         *   It's been a long time since this question was asked, but I ran into this today and after a couple hours, I figured it out. 
         * The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease. 
         * It's created in your Client domain and your Host domain has a proxy to the reference in your Client domain. 
         * This expires after the default 5 minutes unless you override the InitializeLifetimeService() method in your Sponsor class or this sponsor has its own sponsor keeping it from expiring.
         *   Funnily enough, I overcame this by returning Null in the sponsor's InitializeLifetimeService() override to give it an infinite timespan lease, and I created my ISponsor implementation to remove that in a Host MBRO.
         * Source: https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called
        */
        return (null);
    }
}

А потом я использовал этого «нестандартного спонсора» вот так:

// Loader and Container for MarshalByRefObject in another domain
 public class PluginFile : IDisposable
 {
           private RemotingSponsor _sponsor; // Keep instance not to have Sponsor Garbage Collected
           private AppDomain _sandbox;
           private ICustomPlugin[] _plugins; // I do not store real instances of Plugins, but a "CustomPluginProxy" which is known both by main AppDomain and Plugin AppDomain.

    // Constructor : load an assembly file in another AppDomain (sandbox)
    public PluginFile(System.IO.FileInfo f, AppDomainSetup appDomainSetup, Evidence evidence)
    {
        Directory = System.IO.Path.GetDirectoryName(f.FullName) + @"\";
        _sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup);

        _sandbox.Load(typeof(Loader).Assembly.FullName);

        // - Instanciate class "Loader" INSIDE OTHER APPDOMAIN, so we couldn't use new() which would create in main AppDomain.
        _loader = (Loader)Activator.CreateInstance(
            _sandbox,
            typeof(Loader).Assembly.FullName,
            typeof(Loader).FullName,
            false,
            BindingFlags.Public | BindingFlags.Instance,
            null,
            null,
            null,
            null).Unwrap();

        // - Load plugins list for assembly
        _plugins= _loader.LoadPlugins(f.FullName); 


        // - Keep object created in other AppDomain not to be "Garbage Collected". I create a sponsor. The sponsor in registed for object "Lease". The LeaseManager will check lease expiration, and call sponsor. Sponsor can decide to renew lease. I not renewed, the object is garbage collected.
        // - Here is an explanation. Source: https://stackoverflow.com/questions/12306497/how-do-the-isponsor-and-ilease-interfaces-work
        _sponsor = new RemotingSponsor(_loader);

       // Here is my SOLUTION after many hours ! I had to sponsor each MarshalByRefObject (plugins) and not only the main one that contains others !!!
       foreach (ICustomPlugin plugin in Plugins) 
        {
            ILease lease = (ILease)RemotingServices.GetLifetimeService((PluginProxy)plugin);
            lease.Register(_sponsor); // Use the same sponsor. Each Object lease could have as many sponsors as needed, and each sponsor could be registered in many Leases.
        }
    }

 }

Тип PluginProxy имеет ссылку на реальный тип плагина. Действительно, PluginProxy создается внутри Plugin AppDomain и возвращается к основному AppDomain, чтобы позволить ему вызывать плагины, даже если он игнорирует их реальный тип. Таким образом, PluginProxy, который должен быть доступен из основного AppDomain, должен быть сериализован, чтобы пересечь пределы AppDomains. У меня была проблема, потому что я не спонсировал эти MarshalByRefObject (s):

 /// <see cref="/3837937/kak-peredat-neizvestnyi-tip-mezhdu-dvumya-domenami-prilozhenii-net"/>
    [Serializable]
    public class PluginProxy : MarshalByRefObject, ICustomPlugin
    {
        private ICustomPlugin _hostedPlugin;            

        /// <summary>
        /// Parameterless constructor for deserialization 
        /// </summary>
        public PluginProxy()
        {             
        }

        ~PluginProxy()
        {
            Debug.WriteLine("DESTRUCTOR ~PluginProxy");
        }

        /// <summary>
        /// Constructor reserved from real Plugin type
        /// </summary>
        /// <param name="name"></param>
        public PluginProxy(ICustomPlugin hostedPlugin)
        {
            _hostedPlugin = hostedPlugin;
        }

        public PluginName Name => _hostedPlugin.Name;

        public PluginResult Execute(PluginParameters parameters, PluginQuery query)
        {
            return(_hostedPlugin.Execute(parameters, query));
        }
    }

Было трудно решить кучу проблем, надеюсь, это поможет!

Ссылки:

1 голос
/ 27 января 2019

На этот вопрос дан подробный ответ уже в StackOverflow .TL / DR:

  1. Если вы хотите, чтобы переопределение семантики Singleton InitializeLifetimeService возвращало ноль
  2. Используйте ClientSponsor, чтобы сохранить васобъект жив дольше.
1 голос
/ 11 декабря 2018

Это произошло для нас, потому что в одном из наших классов была статическая переменная типа AppDomain. Класс использовался в долго работающей службе Windows. В AppDomain есть метод InitializeLifetimeService, который необходимо переопределить следующим образом:

public override object InitializeLifetimeService(){
    return null;
}

Мы постоянно использовали это как приватную переменную, которая загружала и выгружала некоторые dll-файлы для пользовательской сборки вне логики. Ответ был взят отсюда: msdn ответ

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

Этот вопрос также помог прояснить некоторые вещи о времени жизни: stackoverflow-question

0 голосов
/ 28 мая 2016

В моем случае это происходило с SQL LocalDB, хранящимся в папке App_Data внутри Web проекта.Всякий раз, когда я пытаюсь использовать Package Console для запуска update-database для инициализации моей базы данных Entity Framework с использованием миграций, ничего не происходит.Затем, через некоторое время, я получаю эту ошибку.

Я решил эту проблему путем изменения прав доступа к файлу на App_Data.После исправления, вуаля, все заработало.

0 голосов
/ 18 ноября 2013

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

...