Frage

Ich muss Cross-Appdomain-Anrufe in meiner App verwenden, und manchmal habe ich diese RemotingException:

Objekt '/2FA53226_DA41_42BA_B185_EC7D9C454712/YGIW+xFEGMKHDINJ7G2KPKHC_7.rem' wurde getrennt oder existiert nicht auf dem Server.

Das Zielobjekt lebt noch, ich habe es überprüft.

Upd Ich habe den Haltepunkt im Finalizer des Zielobjekts festgelegt, und es trifft nie. So lebt dieses Objekt und wurde nicht gc'ed.

War es hilfreich?

Lösung

Das liegt wahrscheinlich daran, dass der lokale Müllsammler auf der Serverseite das Objekt sammelt. Sie können dies verhindern, indem Sie das Leasing erneuern. In diesen Artikeln können Sie mehr darüber lesen:

Aktualisieren: Leider sind das MSDN -Magazinausgaben von 2008 oder älter nicht mehr online, sondern nur als .Chm -Dateien, die Sie auf Ihren lokalen Computer herunterladen müssen. Die vorherigen Ausgaben finden Sie in:

Andere Tipps

Dies liegt daran, dass das Lebensdauermanagement auf der Serverseite das Objekt abnimmt, wenn sein Mietvertrag abläuft, damit GC es sammeln kann. Wenn Sie versuchen, es von der Client -Seite zu verwenden, erhalten Sie eine Ausnahme, auch wenn es noch nicht auf dem Server gciert wurde (z. B. weil es noch einen weiteren Hinweis darauf gibt), aber der Mietvertrag ist abgelaufen. Dies soll unvorhersehbares Verhalten vermeiden. Die akzeptierte Antwort bietet eine gute Referenz, wie die Lebensdauer von Remote -.NET -Objekten korrekt verwaltet werden kann.

Ich hatte das gleiche Problem und suchte viele Stunden mit Hilfe vieler Stackoverflow -Posts.

Ich fand endlich das vollständige Problem.

  1. Ich muss einen Sponsor verwenden, um mein Marshalbyrefobject lebendig zu halten.
  2. Ich hatte dann das gleiche Problem wie @User626528: Objekt lebt, aber ich hatte die Ausnahme. In der Tat, Ich musste "all das" "sponsern"Transparentproxy"Instanzen, und nicht nur das wichtigste: Mein Hauptobjekt, das in Sandbox (ein anderer Appdomain) erstellt wurde, gibt Verweise auf andere MarshalbyrefObjects zurück.

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

Meine Klasse "Loader" erbt von MarshalbyrefObject, und ich halte es mit einer Isponsor -Klasse am Leben. Ich weiß, dass "ClientSponsor" in .NET existiert, aber ich hatte keine Möglichkeit zu bestimmen, ob und wann Erneuerung () aufgerufen wird. Deshalb habe ich meine Klasse mit Hilfe der Stackoverflow -Community (Code -Kommentare lesen) gemacht:

/// <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 "benutzerdefinierten Sponsor" wie folgt verwendet:

// 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 realen Plugin -Typ. In der Tat wird das PluginProxy in Plugin Appdomain eingeleitet und in die Haupt -Appdomain zurückgegeben, damit es Plugins anrufen kann, auch wenn er ihren eigentlichen Typ ignoriert. Daher muss die Pluginproxy, die von der Haupt -Appdomain aus zugänglich ist, serialisiert werden, um Appdomains -Grenzen zu überschreiten. Ich hatte ein Problem, weil ich diese MarshalbyrefObject (en) 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 schwierig, Probleme zu lösen, hoffe, das hilft!

Verweise:

Dies geschah für uns, weil wir in einer unserer Klassen eine statische Variable hatten, die vom Typ Appdomain war. Die Klasse wurde in einem langjährigen Windows -Dienst verwendet. AppDomain hat eine InitializELifetimeservice -Methode, die so überschrieben werden muss:

public override object InitializeLifetimeService(){
    return null;
}

Wir verwendeten dies ständig als private Variable, die einige DLLs für eine benutzerdefinierte außerhalb der Logik erstellte Logik lud und entladen ließ. Die Antwort wurde von hier aus genommen: MSDN Antwort

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

Diese Frage hat auch dazu beigetragen, einige Dinge über das Leben zu klären: Stackoverflow-Frage

In meinem Fall war das Problem, dass auf dem Client -Computer ein aktives Netzwerkadapter aktiv war und die virtuellen Netzwerkadapter deaktivierte, das Problem gelöst wurde

In meinem Fall geschah dies mit SQL localdb, die in gespeicherter gespeicherte App_Data Ordner im Inneren Web Projekt. Wann immer ich versuche, Paketkonsole auszuführen update-database Um meine Entity Framework -Datenbank mit Migrationen zu initieren, passiert nichts. Nach einer Weile bekomme ich diesen Fehler.

Ich habe dies gelöst, indem ich Dateiberechtigungen überarbeitet habe App_Data. Sobald es behoben ist, voila, hat es funktioniert.

Diese Frage war Beantwortet bereits ausführlich auf Stackoverflow. Tl/dr:

  1. Wenn Sie die Singleton -Semantik überschreiben möchten InitializeLifetimeService Null zurückzugeben
  2. Verwenden ClientSponsor um dich länger am Leben zu halten.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top