Pregunta

Necesito usar llamadas de apropiamiento cruzado en mi aplicación, y a veces tengo esta Excepción Remotinging:

Objeto '/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem' se ha desconectado o no existe en el servidor.

El objeto objetivo todavía está vivo, lo he revisado.

UPD He establecido el punto de interrupción en el finalizador del objeto de destino, y nunca golpea. Por lo tanto, este objeto está vivo y no fue GC'ed.

¿Fue útil?

Solución

Eso probablemente se deba a que el recolector de basura local en el lado del servidor recoge el objeto. Puede prevenir eso renovando el arrendamiento. Puedes leer más sobre eso en estos artículos:

Actualizar: Desafortunadamente, los números de la revista MSDN de 2008 o más ya no se pueden navegar en línea, sino solo como archivos .chm que tiene que descargar a su máquina local. Los problemas anteriores se pueden encontrar en:

Otros consejos

Esto se debe a que la administración de por vida en el lado del servidor desconecta el objeto cuando expira su arrendamiento, para permitir que GC lo recolecte. Si intenta usarlo desde el lado del cliente, obtendrá una excepción, incluso si aún no se ha GC en el servidor (por ejemplo, porque todavía hay otra referencia) pero el arrendamiento ha expirado. Esto es para evitar un comportamiento impredecible. La respuesta aceptada proporciona una buena referencia sobre cómo administrar correctamente la vida útil de los objetos .NET remotos.

Tuve el mismo problema y busqué muchas horas con la ayuda de muchas publicaciones de Stackoverflow.

Finalmente encontré el problema completo.

  1. Tengo que usar un patrocinador para mantener vivo mi MarshalByRefobject.
  2. Luego tuve el mismo problema que @user626528: el objeto está vivo pero tuve la excepción. En realidad, Necesitaba "patrocinar" todos los "Proparentproxi" instancias, y no solo el principal: mi objeto principal creado en Sandbox (otro AppDomain) devuelve las referencias a otros MarshalByRefobjects.

Aquí está la explicación completa y el caso de uso:

Mi "cargador" de clase hereda de MarshalByRefobject, y lo mantengo vivo con una clase de isponsor. Sé que el "ClientSPonsor" existe en .NET, pero no tenía forma de determinar si se llama a la renovación (), por lo que hice mi clase con la ayuda de la comunidad StackOverflow (lea los comentarios del código):

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

Y luego usé este "patrocinador personalizado" como este:

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

 }

El tipo de pluginproxy tiene una referencia hacia el tipo real de complemento. De hecho, el pluginproxy está instanciado dentro del AppDomain del complemento y se devuelve al appdomain principal, para permitir que llame a complementos incluso si ignora su tipo real. Por lo tanto, el pluginproxy, para ser accesible desde el appdomain principal, debe ser serializado para cruzar los límites de appdomains. Tuve un problema porque no patrociné estos 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));
        }
    }

Fue un montón de problemas difíciles de resolver, ¡espero que esto ayude!

Referencias:

Esto sucedió para nosotros porque teníamos una variable estática en una de nuestras clases que era de tipo Appdomain. La clase se utilizó en un servicio de Windows de larga duración. AppDomain tiene un método InitialInizeLifetimesService que debe anularse así:

public override object InitializeLifetimeService(){
    return null;
}

Estábamos utilizando constantemente esto como la variable privada que cargaba y descargaba algunas DLL para la lógica externa construida a medida. La respuesta ha sido tomada de aquí: respuesta msdn

Debido a que no pudimos cambiar esto en el tiempo de producción, terminamos con el compromiso de reiniciar el servicio de Windows a intervalos aleatorios que son más cortos que la vida útil de la variable de AppDomain estática que, por prueba y error, encontramos que son varios días.

Esta pregunta también ayudó a aclarar algunas cosas sobre la vida: stackoverflow-preguntas

En mi caso, el problema era que en la computadora del cliente, había un adaptador de red virtual activo, deshabilitando los adaptadores de red virtuales, el problema se resolvió

En mi caso, esto estaba sucediendo con SQL LocalDB almacenado en App_Data carpeta dentro Web proyecto. Siempre que intento usar la consola de paquetes para ejecutar update-database Para iniciar la base de datos del marco de mi entidad utilizando migraciones, no sucede nada. Luego, después de un tiempo, recibo ese error.

Resolví esto revisando los permisos de archivo en App_Data. Una vez arreglado, listo, funcionó.

Esta pregunta ha sido Respondido con gran detalle ya en Stackoverflow. TL/DR:

  1. Si quieres anular Singleton Semantics InitializeLifetimeService para devolver nulo
  2. Usar ClientSponsor Para mantener tu objeto vivo por más tiempo.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top