Domanda

Devo usare le chiamate incrociate nella mia app, e talvolta ho questa Exception da remoto:

Oggetto '/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem' è stato disconnesso o non esiste sul server.

L'oggetto target è ancora vivo, l'ho controllato.

UPD Ho impostato Breakpoint nel finalizer dell'oggetto target e non colpisce mai. Quindi, questo oggetto è vivo e non è stato gc.

È stato utile?

Soluzione

Ciò è probabilmente dovuto al fatto che il collettore di immondizia locale sul lato server raccoglie l'oggetto. Puoi impedirlo rinnovando il leasing. Puoi leggere di più su questo in questi articoli:

Aggiornare: Sfortunatamente, la rivista MSDN di 2008 o più non è più sfogliabile online, ma solo come file .chm che devi scaricare sulla macchina locale. I problemi precedenti sono disponibili in:

Altri suggerimenti

Questo perché la gestione a vita sul lato server disconnette l'oggetto quando il contratto di locazione scade, per consentire a GC di raccoglierlo. Se provi a usarlo dal lato client, otterrai un'eccezione, anche se non è stato ancora GC sul server (ad esempio perché c'è ancora un altro riferimento ad esso) ma il contratto di locazione è scaduto. Questo per evitare comportamenti imprevedibili. La risposta accettata fornisce un buon riferimento su come gestire correttamente la durata degli oggetti .NET remoti.

Ho avuto lo stesso problema e ho cercato molte ore con l'aiuto di molti post di StackOverflow.

Ho finalmente trovato il problema completo.

  1. Devo usare uno sponsor per mantenere vivo il mio MarshalByreFobject.
  2. Ho quindi avuto lo stesso problema di @user626528: l'oggetto è vivo ma ho avuto l'eccezione. Infatti, Avevo bisogno di "sponsorizzare" tutto "TransparentProxy"istanze, e non solo quello principale: il mio oggetto principale creato in sandbox (un altro appdomain) restituisce riferimenti ad altri MarshalbyreFobjects.

Ecco la spiegazione completa e il caso d'uso:

La mia classe "Loader" eredita da MarshalByReFobject e lo tengo vivo con una classe isponsor. So che "clientponsor" esiste in .NET, ma non avevo modo di determinare se e quando il rinnovo () viene chiamato, quindi ho fatto la mia classe con l'aiuto della comunità di Stackoverflow (leggi commenti sul codice):

/// <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);
    }
}

E poi ho usato questo "sponsor personalizzato" come questo:

// 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.
        }
    }

 }

Il tipo pluginproxy ha un riferimento al tipo di plug -in reale. In effetti, la pluginProxy è instanziata all'interno del plug -in AppDomain e restituita al principale appdomain, per consentirgli di chiamare i plugin anche se ignora il loro tipo reale. Quindi il pluginproxy, per essere accessibile dal principale appdomain, deve essere serializzato per incrociare i limiti di appdomain. Ho avuto un problema perché non ho sponsorizzato questi MarshalByreFobject:

 /// <see cref="https://stackoverflow.com/questions/4185816/how-to-pass-an-unknown-type-between-two-net-appdomains"/>
    [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));
        }
    }

È stato un sacco di problemi da risolvere, spero che questo aiuti!

Riferimenti:

Questo è successo per noi perché avevamo una variabile statica in una delle nostre classi che era di tipo appdomain. La classe è stata utilizzata in un servizio Windows a lungo in esecuzione. AppDomain ha un metodo InitialiSEtimeservice che deve essere annullato in questo modo:

public override object InitializeLifetimeService(){
    return null;
}

Usammo costantemente questo come variabile privata che caricava e scaricava alcune DLL per la logica esterna su misura. La risposta è stata presa da qui: Risposta MSDN

Poiché non siamo stati in grado di modificarlo a tempo di produzione, abbiamo concluso con un compromesso di riavvio del servizio Windows a intervalli casuali che sono più brevi della durata della variabile appdomain statica che per prova ed errore abbiamo scoperto che sono diversi giorni.

Questa domanda ha anche contribuito a chiarire alcune cose sulla vita: Domanda stackoverflow

Nel mio caso, il problema era che nel computer client era attivo un adattatore di rete virtuale, disabilitando gli adattatori di rete virtuale, il problema è stato risolto

Nel mio caso, questo stava accadendo con SQL LocalDB memorizzato App_Data cartella all'interno Web progetto. Ogni volta che provo a utilizzare il pacchetto per eseguire update-database Per iniziare il database del mio framework entità utilizzando le migrazioni, non succede nulla. Poi dopo un po ', ottengo quell'errore.

L'ho risolto rivedendo le autorizzazioni App_Data. Una volta risolto, voilà, ha funzionato.

Questa domanda è stata ha risposto in modo molto dettagliato già su StackOverflow. Tl/dr:

  1. Se vuoi Singleton Semantics Override InitializeLifetimeService per restituire null
  2. Uso ClientSponsor per mantenerti in vita più a lungo.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top