tags:

views:

42

answers:

3

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?

+1  A: 

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.

Justin Breitfeller
That is correct. The domain gets unloaded and then i try to dispose the next plugin...Can i set both as accepted?
klundby
Im pretty certain you can only mark one as accepted.
Justin Breitfeller
+1  A: 

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.

Hans Passant
That is correct. The domain gets unloaded and then i try to dispose the next plugin...Can i set both as accepted?
klundby
+1  A: 

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:

try
    {
        // Catch here -- if we are finalizing we may have already
        // finalized the weak handle in the table or the lease may
        // have already been unloaded.
        r.Lease.Unregister(Sponsor.instance);
    }
    catch (InvalidOperationException) { }
    catch (AppDomainUnloadedException) { }

I will update the post.

Brian