Search code examples
c#vb.netremotingappdomainobject-lifetime

MarshalByRefObject Lifetime


I have a .net WinForms application that loads plugins (dlls) into their own AppDomains, each dll gets its own AppDomain using domain.CreateInstanceAndUnwrap(). All i want is, that these objects remain connected forever (till the application stops).
The InitialLeaseTime is 5 minutes, but i can't find a way to change that. .. I tried overriding InitializeLifetimeService() of the remote object:

Public Overrides Function InitializeLifetimeService() As Object  
     Return Nothing  
End Function

Here I get a Typeload-Exception, saying that this would break the inheritance rules. Adding

<SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.Infrastructure)>
<SecuritySafeCritical>

doesn't change anything.

Then:

Dim tmpObj As Object = domain.CreateInstanceAndUnwrap(type.AssemblyName, type.TypeName)
Dim tmpRemote As tmpRemoteType = CType(tmpObj, tmpRemoteType)

Dim lifetimeService As Object = Runtime.Remoting.RemotingServices.GetLifetimeService(tmpRemote)
Dim lease As ILease = TryCast(lifetimeService, ILease)
If (lease IsNot Nothing) Then
     lease.Register(_sponsor)
 End If

Doesn't do it neither, because somehow the Renewal() method of the sponsor (not shown here) is never called.

Calling

lease.Renew(TimeSpan.FromMinutes(300))

directly changes the CurrentLeaseTime but not the InitialLeaseTime of the lease.

Finally i tried calling the shared (static) property LeaseTime, which actually led to a change of CurrentLeaseTime at the beginning of the Lease, but again NOT the InitialLeaseTime, which seems to end after 5 minutes and my remote object being gc'ed:

LifetimeServices.RenewOnCallTime = System.TimeSpan.FromMinutes(300)

Any help is appreciated, Thx!


Solution

  • Not sure what's going on, but here's how it works

    var sponsor = new Sponsor();  // manages lifetime of the object in otherDomain
    var target = otherDomain.CreateInstanceFromAndUnwrap(assemblyFilename, typeFullName) 
        as MarshalByRefObject;
    
    var lease = target.InitializeLifetimeService() as ILease;
    lease.Register(sponsor);
    

    In this case, it is only important that you retain references to target (obvious) and sponsor. Sponsor is a class that manages the subscription:

    class Sponsor : MarshalByRefObject, ISponsor
    {
        public bool Release { get; set; }
    
        public TimeSpan Renewal(ILease lease)
        {
            // if any of these cases is true
            if (lease == null || lease.CurrentState != LeaseState.Renewing || Release)
                return TimeSpan.Zero; // don't renew
            return TimeSpan.FromSeconds(1); // renew for a second, or however long u want
        }
    }
    

    When you're done with it, simply set Release to true on the sponsor and let it go. You could also do this by implementing IDisposable on Sponsor to handle this, if that tickles your fancy.