web-dev-qa-db-de.com

Ausnahme "Das Objekt wurde getrennt oder ist am Server nicht vorhanden"

Ich muss App-übergreifende Aufrufe in meiner App verwenden, und manchmal habe ich diese RemotingException:

Objekt '/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem' wurde getrennt oder ist auf dem Server nicht vorhanden. 

Das Zielobjekt ist noch am Leben, ich habe es überprüft.

UPD Ich habe im Finalizer des Zielobjekts einen Haltepunkt gesetzt, der nie getroffen wird. Daher lebt dieses Objekt und wurde nicht GC-basiert.

41
user626528

Dies liegt wahrscheinlich daran, dass der lokale Garbage Collector auf der Serverseite das Objekt erfasst. Sie können dies verhindern, indem Sie das Leasing verlängern. Mehr dazu lesen Sie in diesen Artikeln:

Update: Leider können die MSDN Magazine-Ausgaben von 2008 oder älter nicht mehr online durchsucht werden, sondern nur noch als .chm-Dateien, die Sie auf Ihren lokalen Computer herunterladen müssen. Die vorherigen Ausgaben finden Sie in:

33
Marius Bancila

Dies liegt daran, dass das Lifetime-Management auf der Serverseite das Objekt nach Ablauf seiner Lease-Verbindung trennt, damit GC es abholen kann. Wenn Sie versuchen, die Anwendung auf der Clientseite zu verwenden, wird eine Ausnahme angezeigt, auch wenn sie noch nicht auf dem Server GC-geprüft wurde (z. B. weil es noch einen anderen Verweis darauf gibt), die Lease jedoch abgelaufen ist. Dies dient dazu, unvorhersehbares Verhalten zu vermeiden. Die akzeptierte Antwort bietet eine gute Referenz, wie die Lebensdauer von Remote-.NET-Objekten korrekt verwaltet werden kann.

15

Ich hatte das gleiche Problem und habe viele Stunden mit Hilfe von StackOverflow-Posts gesucht.

Endlich habe ich die komplette Ausgabe gefunden.

  1. Ich muss einen Sponsor einsetzen, um mein MarshalByRefObject am Leben zu erhalten.
  2. Ich hatte dann das gleiche Problem als @ user626528: Objekt lebt, aber ich hatte die Ausnahme. Tatsächlich musste ich "ALL THE" TransparentProxy "-Instanzen sponsern, und nicht nur das Hauptinhalt: Mein in SandBox (einer anderen AppDomain) erstelltes Hauptobjekt gibt Verweise auf andere MarshalByRefObjects zurück.

Hier ist die vollständige Erklärung und der Anwendungsfall:

Meine Klasse "Loader" erbt von MarshalByRefObject und ich halte es mit einer ISponsor-Klasse am Leben. Ich weiß, dass "ClientSponsor" in .NET vorhanden ist, aber ich konnte nicht feststellen, ob und wann Renewal () aufgerufen wird. Daher habe ich meine Klasse mit Hilfe der StackOverflow-Community erstellt (Code-Kommentare lesen):

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

Und dann habe ich diesen "Custom Sponsor" so benutzt:

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

 }

Der PluginProxy-Typ hat eine Referenz auf den echten Plugin-Typ. Tatsächlich wird PluginProxy in Plugin AppDomain instanziiert und an Main AppDomain zurückgegeben, damit Plugins aufgerufen werden können, selbst wenn der tatsächliche Typ ignoriert wird. Daher muss das PluginProxy, um von der Haupt-AppDomain aus erreichbar zu sein, serialisiert werden, um die AppDomains-Grenzen zu überschreiten. Ich hatte ein Problem, weil ich diese MarshalByRefObjects nicht gesponsert habe:

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

Es war ein schwieriger Haufen Probleme zu lösen, hoffe das hilft!

Verweise:

2
Elo

Dies geschah für uns, weil wir in einer unserer Klassen eine statische Variable vom Typ AppDomain hatten. Die Klasse wurde in einem lange laufenden Windows-Dienst verwendet. __ AppDomain verfügt über eine InitializeLifetimeService-Methode, die wie folgt überschrieben werden muss:

public override object InitializeLifetimeService(){
    return null;
}

Wir verwendeten dies ständig als private Variable, mit der einige DLLs für benutzerdefinierte Logik außerhalb geladen und entladen wurden .. Die Antwort wurde hier entnommen: msdn answer

Da wir dies nicht zur Produktionszeit ändern konnten, endeten wir mit einem Kompromiss, den Windows-Dienst in zufälligen Intervallen neu zu starten, die kürzer sind als die Lebensdauer der statischen AppDomain-Variablen, die wir durch Ausprobieren festgestellt haben, dass es mehrere Tage ist.

Diese Frage half auch einige Dinge über die Lebensdauer zu klären: stackoverflow-question

1
Allen

in meinem Fall bestand das Problem darin, dass auf dem Clientcomputer ein virtueller Netzwerkadapter aktiv war und die virtuellen Netzwerkadapter deaktiviert wurden. Das Problem wurde gelöst

0
Ismael

Diese Frage wurde bereits in StackOverflow ausführlich beantwortet . TL/DR:

  1. Wenn Sie möchten, dass die Singleton-Semantik überschreibt InitializeLifetimeService gibt null zurück
  2. Verwenden Sie ClientSponsor , um Ihr Objekt länger am Leben zu erhalten.
0
cdiggins

In meinem Fall geschah dies mit SQL LocalDB, die im App_Data-Ordner im Web-Projekt gespeichert war. Wenn ich versuche, Package Console zum Ausführen von update-database zum Initiieren meiner Entity Framework-Datenbank mithilfe von Migrationen zu verwenden, geschieht nichts. Nach einer Weile bekomme ich diesen Fehler.

Ich habe das Problem gelöst, indem ich die Dateiberechtigungen für App_Data überarbeitete. Einmal fixiert, voila, es hat funktioniert.

0
Korayem