AppDomain and MarshalByRefObject life time : how to avoid RemotingException?

后端 未结 10 2036
时光取名叫无心
时光取名叫无心 2020-12-04 08:53

When a MarshalByRef object is passed from an AppDomain (1) to another (2), if you wait 6 mins before calling a method on it in the second AppDomain (2) you will get a Remoti

10条回答
  •  醉酒成梦
    2020-12-04 09:10

    I finally found a way to do client activated instances but it involves managed code in Finalizer :( I specialized my class for CrossAppDomain communication but you may modify it and try in others remoting. Let me know if you find any bug.

    The two following classes must be in an assembly loaded in all application domains involved.

      /// 
      /// Stores all relevant information required to generate a proxy in order to communicate with a remote object.
      /// Disconnects the remote object (server) when finalized on local host (client).
      /// 
      [Serializable]
      [EditorBrowsable(EditorBrowsableState.Never)]
      public sealed class CrossAppDomainObjRef : ObjRef
      {
        /// 
        /// Initializes a new instance of the CrossAppDomainObjRef class to
        /// reference a specified CrossAppDomainObject of a specified System.Type.
        /// 
        /// The object that the new System.Runtime.Remoting.ObjRef instance will reference.
        /// 
        public CrossAppDomainObjRef(CrossAppDomainObject instance, Type requestedType)
          : base(instance, requestedType)
        {
          //Proxy created locally (not remoted), the finalizer is meaningless.
          GC.SuppressFinalize(this);
        }
    
        /// 
        /// Initializes a new instance of the System.Runtime.Remoting.ObjRef class from
        /// serialized data.
        /// 
        /// The object that holds the serialized object data.
        /// The contextual information about the source or destination of the exception.
        private CrossAppDomainObjRef(SerializationInfo info, StreamingContext context)
          : base(info, context)
        {
          Debug.Assert(context.State == StreamingContextStates.CrossAppDomain);
          Debug.Assert(IsFromThisProcess());
          Debug.Assert(IsFromThisAppDomain() == false);
          //Increment ref counter
          CrossAppDomainObject remoteObject = (CrossAppDomainObject)GetRealObject(new StreamingContext(StreamingContextStates.CrossAppDomain));
          remoteObject.AppDomainConnect();
        }
    
        /// 
        /// Disconnects the remote object.
        /// 
        ~CrossAppDomainObjRef()
        {
          Debug.Assert(IsFromThisProcess());
          Debug.Assert(IsFromThisAppDomain() == false);
          //Decrement ref counter
          CrossAppDomainObject remoteObject = (CrossAppDomainObject)GetRealObject(new StreamingContext(StreamingContextStates.CrossAppDomain));
          remoteObject.AppDomainDisconnect();
        }
    
        /// 
        /// Populates a specified System.Runtime.Serialization.SerializationInfo with
        /// the data needed to serialize the current System.Runtime.Remoting.ObjRef instance.
        /// 
        /// The System.Runtime.Serialization.SerializationInfo to populate with data.
        /// The contextual information about the source or destination of the serialization.
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
          Debug.Assert(context.State == StreamingContextStates.CrossAppDomain);
          base.GetObjectData(info, context);
          info.SetType(typeof(CrossAppDomainObjRef));
        }
      }
    

    And now the CrossAppDomainObject, your remoted object must inherit from this class instead of MarshalByRefObject.

      /// 
      /// Enables access to objects across application domain boundaries.
      /// Contrary to MarshalByRefObject, the lifetime is managed by the client.
      /// 
      public abstract class CrossAppDomainObject : MarshalByRefObject
      {
        /// 
        /// Count of remote references to this object.
        /// 
        [NonSerialized]
        private int refCount;
    
        /// 
        /// Creates an object that contains all the relevant information required to
        /// generate a proxy used to communicate with a remote object.
        /// 
        /// The System.Type of the object that the new System.Runtime.Remoting.ObjRef will reference.
        /// Information required to generate a proxy.
        [EditorBrowsable(EditorBrowsableState.Never)]
        public sealed override ObjRef CreateObjRef(Type requestedType)
        {
          CrossAppDomainObjRef objRef = new CrossAppDomainObjRef(this, requestedType);
          return objRef;
        }
    
        /// 
        /// Disables LifeTime service : object has an infinite life time until it's Disconnected.
        /// 
        /// null.
        [EditorBrowsable(EditorBrowsableState.Never)]
        public sealed override object InitializeLifetimeService()
        {
          return null;
        }
    
        /// 
        /// Connect a proxy to the object.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void AppDomainConnect()
        {
          int value = Interlocked.Increment(ref refCount);
          Debug.Assert(value > 0);
        }
    
        /// 
        /// Disconnects a proxy from the object.
        /// When all proxy are disconnected, the object is disconnected from RemotingServices.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void AppDomainDisconnect()
        {
          Debug.Assert(refCount > 0);
          if (Interlocked.Decrement(ref refCount) == 0)
            RemotingServices.Disconnect(this);
        }
      }
    

提交回复
热议问题