I have a application that uses plugins. I load the plugins in another appdomain. I use the RemoteHandle class from http://www.pocketsilicon.com/post/Things-That-Make-My-Life-Hell-Part-1-App-Domains.aspx to keep object from being garbage collected after 5 minutes.
This works great as long as my application is running, but when it is shutting down i get a InvalidOperationException when Unregistering
internal static void Unregister(MarshalByRefObject value)
{
if (value != null && RemotingServices.IsTransparentProxy(value))
{
lock (_syncLock)
{
ReferencedLease r;
if (_leaseReferences.TryGetValue(value, out r) && --r.ReferenceCount <= 0)
{
// Note: Dictionary clears key and value from bucket list upon remove.
_leaseReferences.Remove(value);
r.Lease.Unregister(_instance); // <----- Here i get the exception
}
}
}
}
Stacktrace:
System.InvalidOperationException: Handle is not initialized.
at System.WeakReference.set_Target(Object value)
at System.Runtime.Remoting.IdentityHolder.SetIdentity(Identity idObj, String URI, DuplicateIdentityOption duplicateOption)
at System.Runtime.Remoting.IdentityHolder.FindOrCreateIdentity(String objURI, String URL, ObjRef objectRef)
at System.Runtime.Remoting.RemotingServices.InternalUnmarshal(ObjRef objectRef, Object proxy, Boolean fRefine)
at System.Runtime.Remoting.ObjRef.GetRealObjectHelper()
at System.Runtime.Remoting.Lifetime.ILease.Unregister(ISponsor obj)
at Quick3PlugInManager.Sponsor.Unregister(MarshalByRefObject value)
at Quick3PlugInManager.RemoteHandle`1.Dispose(Boolean disposing)
at Quick3PlugInManager.RemoteHandle`1.Finalize()
Why do i get that exception?
You get this exception because the code is running in the finalizer thread. You are referencing an object that is already finalized. The order in which objects are finalized is not deterministic.
That's what causes it, what you'd do about it is unclear to me from the snippet.
I would subscribe to the app domains Unload event and see if the application domain has been unloaded already. If so, then I suspect that you don't need to unregister that handle any longer (just swallow the exception) because the CLR has done it for you. This is just a theory, but it might give you more information.
I wrote the original post on Pocket Silicon. We have had this issue too and our current work around is to catch exceptions here. I'd love a way to tell if the foreign domain is still alive but haven't found one (yes, I could have that domain tell me when it is going away, but I don't want additional requirements placed on the remoted objects).
Here is the catch block we're currently using:
I will update the post.