OnDemand Assemply Load - PartII

 08-Sep-2012   NityaPrakash     Assembly  RemoteObject    Comments  0

In last article Part1, I tried to explain how can we load assembly on demand and unload.  In that article, we created object in another appDomain, but referenced and used in current domain.  But, after some time, when try to access that object, it will start throwing exception (Object '/e94a9f11_6fd1_4e39_b40e_aaff754cceee/dqgr5+ytjkcgsjxttifi9qgr_3.rem' has been disconnected or does not exist at the server).  Reason behind is, object is considered as remote object, and AppDomain where it is created, considered as server.

What is happening

The .NET manages the lifecycle of object using garbage collection.  It keeps track of memory allocation and objects accessed by all the clients in an AppDomain.  Incase of a remote object, accessed across appDomains, processes or machines, the object may not have local client. And GC will not find reference to the object and assume as garbage and release the memory, even remote client on another machine, process or appDomain using it.  After garbage collected the remote object at server side, client tries to access the object, above error occurs. 

Managing the Lifetime of Remote .NET Object

In this article I am going to discuss how did I manage to resolve above error.  To know more and detail about read the article from Juval Lowy Managing the Lifetime of Remote .NET Object with Leasing and Sponsorship.

There are two different way to manage the lifetime of the object in current scenario:

Configuring lifetime of the object when designing the class

Class which is remotely accessible must be inherited by MarshaByRefObject class.  And class should override InitializeLifetimeService method which returns lease object.


    public abstract class MyAddIn: MarshalByRefObject, IMyAddin
    {
        public override object InitializeLifetimeService()
        {
            ILease lease = (ILease)base.InitializeLifetimeService();

            lease.InitialLeaseTime = TimeSpan.FromMinutes(30);
            lease.RenewOnCallTime = TimeSpan.FromMinutes(15);
            return lease;
        }
        public abstract string ShowMessage();


        public abstract void Increment();
    }

In this case remote object will remain connected to server for 30 minutes. After that same error will occur, if client try to access the object. However, if whenever object is just about to expire and client makes a call to the object, lease of the object extended up to the time specified in RenewOnCallTime property of lease.  To keep it alive, object must be called before it expires.  Once expired, it cannot be released. Below formula works here to determine the current lease



current lease time = MAX(lease time - expired time, renewal time)



If the object being called at regular interval, above method works well.  However, most of the time client itself don�t know when object required. Then below solution works perfectly.

Sponsorship

Sponsor is a third party object that .Net Remoting framework consult with when a lease expires.  It gives this a opportunity to renew the lease.  The sponsor must implement the ISponsor interface.


    public class MySponser :MarshalByRefObject, ISponsor
    {
        public TimeSpan Renewal(ILease lease)
        {
            Console.WriteLine(lease.CurrentState == LeaseState.Active);

            return lease.InitialLeaseTime; 
        }
    }

In above code, I am instructing sponsor to renew the lease up to the time that initially leased. Sponsor must derive the MarshalByRefObject so it should resides at client side, and it can base its decision of the renewal time on client-side events or properties that it is monitoring.  Client must manage its reference through out the time until remote object requires.  We have register the remote object with sponsor as soon as create object also it should be un registered when not required.

Whenever I am creating object of MyAddIn, registering with Sponsor:


                MyAddIn addin = appDomain.CreateInstanceAndUnwrap(domainSetup.ApplicationName, 
					domainSetup.ApplicationName + ".MyClass") as MyAddIn;

                _addIns.Add(name_, addin);

                ISponsor sponer_ = new MySponser();
                ILease lease = (ILease)RemotingServices.GetLifetimeService(addin);
                lease.Register(sponer_);
                _sponserList.Add(name_, sponer_);

Similarly it needs to unregister. I am unregistering when unloading the appDomains


        public void UnRegisterSponser(string key)
        {

            ILease lease = (ILease)
    	    RemotingServices.GetLifetimeService(_addIns[key]);

            lease.Unregister(_sponserList[key]);
        }

Final Words

I want to close the chapter here. I implemented this sponsorship based on I studied in article by Jual Lowy�s Managing the Lifetime of Remote .NET Object with Leasing and Sponsorship.


Nitya Prakash Sharma has over 10 years of experience in .NET technology. He is currently working as Senior Consultant in industry. He is always keen to learn new things in Technology and eager to apply wherever is possible. He is also has interest in Photography, sketching and painting.

My Blog
Post Comment

COMMENTS