c# - La excepción "Objeto ha sido desconectado o no existe en el servidor"
.net clr (5)
En mi caso, esto estaba sucediendo con SQL LocalDB almacenado en la carpeta App_Data
dentro del proyecto Web
. Cada vez que intento usar Package Console para ejecutar update-database
para iniciar mi update-database
de Entity Framework utilizando migraciones, no ocurre nada. Luego, después de un tiempo, obtengo ese error.
Lo resolví revisando los permisos de archivo en App_Data
. Una vez arreglado, voila, funcionó.
Necesito usar llamadas de dominio cruzado en mi aplicación, y a veces tengo esta excepción RemotingException:
El objeto ''/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem'' ha sido desconectado o no existe en el servidor.
El objeto de destino todavía está vivo, lo he comprobado.
UPD He establecido un punto de corte en el finalizador del objeto de destino, y nunca golpea. Por lo tanto, este objeto está vivo y no fue GC.
Eso es probablemente porque el recolector de basura local en el lado del servidor recoge el objeto. Puede evitar eso renovando el arrendamiento. Puedes leer más sobre esto en estos artículos:
- Administrar toda la vida de los objetos de .NET remotos con leasing y patrocinio
- CLR Inside Out: administración de objetos de por vida
Actualización : Desafortunadamente, los problemas de MSDN Magazine desde 2008 o anteriores ya no se pueden explorar en línea, sino solo como archivos .chm que debe descargar a su máquina local. Los números anteriores se pueden encontrar en:
- Gestionando la vida útil de los objetos .NET remotos con leasing y patrocinio en diciembre de 2003
- CLR Inside Out: administración de Object Lifetime en noviembre de 2007
Esto se debe a que la administración de Lifetime del lado del servidor desconecta el objeto cuando expira su concesión, para permitir que GC lo recopile. Si intenta usarlo desde el lado del cliente, obtendrá una excepción, incluso si aún no se ha GC''d en el servidor (por ejemplo, porque todavía hay otra referencia) pero el contrato 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 de .NET remotos.
Tuve el mismo problema y busqué muchas horas con la ayuda de muchas publicaciones de .
Finalmente encontré el problema completo.
- Tengo que usar un patrocinador para mantener vivo mi MarshalByRefObject.
- Luego tuve el mismo problema que @ user626528: el objeto está vivo pero tuve la excepción. De hecho, necesitaba "patrocinar" TODAS las instancias de " TransparentProxy " , y no solo la principal: mi Objeto principal creado en SandBox (otro AppDomain) devuelve referencias a otros MarshalByRefObjects.
Aquí está el caso completo de explicación y uso:
Mi clase "Loader" hereda de MarshalByRefObject y la mantengo viva con una clase ISponsor. Sé que existe "ClientSponsor" en .NET, pero no tenía manera de determinar si se llama a Renewal (), así que hice mi clase con la ayuda de la comunidad de (lea los comentarios del código):
/// <see cref="https://.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://.com/questions/18680664/remoting-sponsor-stops-being-called
*/
return (null);
}
}
Y luego usé este "patrocinador personalizado" de esta manera:
// 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://.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 PluginProxy tiene una referencia hacia el tipo de complemento real. De hecho, el PluginProxy se instancia dentro de Plugin AppDomain, y se devuelve al AppDomain principal, para permitirle llamar a Plugins, incluso si ignora su tipo real. Por lo tanto, el PluginProxy, para ser accesible desde AppDomain principal, debe ser serializado para cruzar los límites de AppDomains. Tuve un problema porque no patrociné estos MarshalByRefObject (s):
/// <see cref="https://.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
en mi caso, el problema era que en la computadora cliente, había un adaptador de red virtual activo, deshabilitaba los adaptadores de red virtuales, el problema estaba resuelto