C# AppDomain和MarshallByRefObject生命周期:如何避免RemotingException?

C# AppDomain和MarshallByRefObject生命周期:如何避免RemotingException?,c#,.net,remoting,appdomain,object-lifetime,C#,.net,Remoting,Appdomain,Object Lifetime,当MarshalByRef对象从一个AppDomain(1)传递到另一个AppDomain(2)时,如果您在第二个AppDomain(2)中对其调用方法之前等待6分钟,您将获得RemotingException: System.Runtime.Remoting.RemotingException: 对象[…]已断开连接或 服务器上不存在 有关此isse的一些文档: -实例生命周期,cbrumme说“我们应该解决这个问题。”:( 如果我错了,请纠正我:如果InitializeLifetime

当MarshalByRef对象从一个AppDomain(1)传递到另一个AppDomain(2)时,如果您在第二个AppDomain(2)中对其调用方法之前等待6分钟,您将获得RemotingException:

System.Runtime.Remoting.RemotingException: 对象[…]已断开连接或 服务器上不存在

有关此isse的一些文档:

  • -实例生命周期,cbrumme说“我们应该解决这个问题。”:(
如果我错了,请纠正我:如果InitializeLifetimeService返回null,则只有在卸载AppDomain 2时才能在AppDomain 1中收集对象,即使收集了代理


是否有一种方法可以禁用生存期并使代理(在AppDomain 2中)和对象(在AppDomain1中)保持活动状态,直到代理最终确定?可能是使用ISponsor…?

我终于找到了一种方法来执行客户端激活的实例,但它涉及到终结器中的托管代码:( 我将我的类专门用于跨AppDomain通信,但您可以修改它并尝试其他远程处理。 如果你发现任何错误,请告诉我

以下两个类必须位于加载到所有相关应用程序域中的程序集中

  /// <summary>
  /// 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).
  /// </summary>
  [Serializable]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public sealed class CrossAppDomainObjRef : ObjRef
  {
    /// <summary>
    /// Initializes a new instance of the CrossAppDomainObjRef class to
    /// reference a specified CrossAppDomainObject of a specified System.Type.
    /// </summary>
    /// <param name="instance">The object that the new System.Runtime.Remoting.ObjRef instance will reference.</param>
    /// <param name="requestedType"></param>
    public CrossAppDomainObjRef(CrossAppDomainObject instance, Type requestedType)
      : base(instance, requestedType)
    {
      //Proxy created locally (not remoted), the finalizer is meaningless.
      GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Initializes a new instance of the System.Runtime.Remoting.ObjRef class from
    /// serialized data.
    /// </summary>
    /// <param name="info">The object that holds the serialized object data.</param>
    /// <param name="context">The contextual information about the source or destination of the exception.</param>
    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();
    }

    /// <summary>
    /// Disconnects the remote object.
    /// </summary>
    ~CrossAppDomainObjRef()
    {
      Debug.Assert(IsFromThisProcess());
      Debug.Assert(IsFromThisAppDomain() == false);
      //Decrement ref counter
      CrossAppDomainObject remoteObject = (CrossAppDomainObject)GetRealObject(new StreamingContext(StreamingContextStates.CrossAppDomain));
      remoteObject.AppDomainDisconnect();
    }

    /// <summary>
    /// Populates a specified System.Runtime.Serialization.SerializationInfo with
    /// the data needed to serialize the current System.Runtime.Remoting.ObjRef instance.
    /// </summary>
    /// <param name="info">The System.Runtime.Serialization.SerializationInfo to populate with data.</param>
    /// <param name="context">The contextual information about the source or destination of the serialization.</param>
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      Debug.Assert(context.State == StreamingContextStates.CrossAppDomain);
      base.GetObjectData(info, context);
      info.SetType(typeof(CrossAppDomainObjRef));
    }
  }
//
///存储生成代理以与远程对象通信所需的所有相关信息。
///在本地主机(客户端)上完成时断开远程对象(服务器)的连接。
/// 
[可序列化]
[EditorBrowsable(EditorBrowsableState.Never)]
公共密封类CrossAppDomainObjRef:ObjRef
{
/// 
///将CrossAppDomainObjRef类的新实例初始化为
///引用指定System.Type的指定CrossAppDomainObject。
/// 
///新System.Runtime.Remoting.ObjRef实例将引用的对象。
/// 
公共CrossAppDomainObjRef(CrossAppDomainObject实例,类型requestedType)
:base(实例,requestedType)
{
//本地创建的代理(非远程),终结器没有意义。
总干事(本);
}
/// 
///从初始化System.Runtime.Remoting.ObjRef类的新实例
///序列化数据。
/// 
///保存序列化对象数据的对象。
///有关异常源或目标的上下文信息。
私有CrossAppDomainObjRef(SerializationInfo信息,StreamingContext上下文)
:base(信息、上下文)
{
Assert(context.State==streamingContextState.CrossAppDomain);
Assert(IsFromThisProcess());
Assert(IsFromThisAppDomain()==false);
//增量参考计数器
CrossAppDomainObject remoteObject=(CrossAppDomainObject)GetRealObject(新StreamingContext(StreamingContextState.CrossAppDomain));
remoteObject.AppDomainConnect();
}
/// 
///断开远程对象的连接。
/// 
~CrossAppDomainObjRef()
{
Assert(IsFromThisProcess());
Assert(IsFromThisAppDomain()==false);
//减量参考计数器
CrossAppDomainObject remoteObject=(CrossAppDomainObject)GetRealObject(新StreamingContext(StreamingContextState.CrossAppDomain));
remoteObject.AppDomainDisconnect();
}
/// 
///将指定的System.Runtime.Serialization.SerializationInfo填充为
///序列化当前System.Runtime.Remoting.ObjRef实例所需的数据。
/// 
///要使用数据填充的System.Runtime.Serialization.SerializationInfo。
///有关序列化的源或目标的上下文信息。
公共覆盖无效GetObjectData(SerializationInfo、StreamingContext上下文)
{
Assert(context.State==streamingContextState.CrossAppDomain);
base.GetObjectData(信息、上下文);
info.SetType(typeof(CrossAppDomainObjRef));
}
}
现在是CrossAppDomainObject,您的远程对象必须继承自该类,而不是MarshalByRefObject

  /// <summary>
  /// Enables access to objects across application domain boundaries.
  /// Contrary to MarshalByRefObject, the lifetime is managed by the client.
  /// </summary>
  public abstract class CrossAppDomainObject : MarshalByRefObject
  {
    /// <summary>
    /// Count of remote references to this object.
    /// </summary>
    [NonSerialized]
    private int refCount;

    /// <summary>
    /// Creates an object that contains all the relevant information required to
    /// generate a proxy used to communicate with a remote object.
    /// </summary>
    /// <param name="requestedType">The System.Type of the object that the new System.Runtime.Remoting.ObjRef will reference.</param>
    /// <returns>Information required to generate a proxy.</returns>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public sealed override ObjRef CreateObjRef(Type requestedType)
    {
      CrossAppDomainObjRef objRef = new CrossAppDomainObjRef(this, requestedType);
      return objRef;
    }

    /// <summary>
    /// Disables LifeTime service : object has an infinite life time until it's Disconnected.
    /// </summary>
    /// <returns>null.</returns>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public sealed override object InitializeLifetimeService()
    {
      return null;
    }

    /// <summary>
    /// Connect a proxy to the object.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public void AppDomainConnect()
    {
      int value = Interlocked.Increment(ref refCount);
      Debug.Assert(value > 0);
    }

    /// <summary>
    /// Disconnects a proxy from the object.
    /// When all proxy are disconnected, the object is disconnected from RemotingServices.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public void AppDomainDisconnect()
    {
      Debug.Assert(refCount > 0);
      if (Interlocked.Decrement(ref refCount) == 0)
        RemotingServices.Disconnect(this);
    }
  }
//
///允许跨应用程序域边界访问对象。
///与MarshalByRefObject相反,生存期由客户端管理。
/// 
公共抽象类CrossAppDomainObject:MarshalByRefObject
{
/// 
///对此对象的远程引用计数。
/// 
[非串行化]
私人int refCount;
/// 
///创建包含所需的所有相关信息的对象
///生成用于与远程对象通信的代理。
/// 
///新System.Runtime.Remoting.ObjRef将引用的对象的System.Type。
///生成代理所需的信息。
[EditorBrowsable(EditorBrowsableState.Never)]
公共密封覆盖ObjRef CreateObjRef(类型requestedType)
{
CrossAppDomainObjRef objRef=新的CrossAppDomainObjRef(此,requestedType);
返回objRef;
}
/// 
///禁用生存期服务:对象在断开连接之前有无限的生存期。
/// 
///空。
[EditorBrowsable(EditorBrowsableState.Never)]
公共密封覆盖对象初始化ElifetimeService()
{
返回null;
}
/// 
///将代理连接到对象。
/// 
[EditorBrowsable(EditorBrowsableState.Never)]
public void AppDomainConnect()
{
int值=联锁增量(参考计数);
断言(值>0);
}
/// 
///断开代理与对象的连接。
///断开所有代理连接后,对象将与远程服务断开连接。
/// 
[EditorBrowsable(EditorBrowsableState.Never)]
public void AppDomainDisconnect()
{
断言(refCount>0);
if(联锁减量(参考计数)==0)
远程服务。断开(此);
}
}

不幸的是,当AppDomains用于插件目的时,此解决方案是错误的(插件程序集不得加载到主appdomain中)

GetRealObject()是ca
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
  return null;
}
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
  return null;
}
public class MarshalByRefObjectPermanent : MarshalByRefObject
{
    public override object InitializeLifetimeService()
    {
        return null;
    }

    ~MarshalByRefObjectPermanent()
    {
        RemotingServices.Disconnect(this);
    }
}
public static class MyClientClass
{
    private static MarshalByRefObject remoteClass;

    static MyClientClass()
    {
        CreateRemoteInstance();
    }

    // ...

    public static void DoStuff()
    {
        // Before doing stuff, check if the remote object is still reachable
        try {
            remoteClass.GetLifetimeService();
        }
        catch(RemotingException) {
            CreateRemoteInstance(); // Re-create remote instance
        }

        // Now we are sure the remote class is reachable
        // Do actual stuff ...
    }

    private static void CreateRemoteInstance()
    {
        remoteClass = (MarshalByRefObject)AppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(remoteClassPath, typeof(MarshalByRefObject).FullName);
    }
}
class MyMarshaledObject : MarshalByRefObject
{
    public bool DoSomethingRemote() 
    {
      // ... execute some code remotely ...
      return true; 
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public override object InitializeLifetimeService()
    {
      return null;
    }
}
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Lifetime;
namespace RemotingSamples
{

   class HelloClient
   {
       static void Main()
      {
         // Register a channel.
         TcpChannel myChannel = new TcpChannel ();
         ChannelServices.RegisterChannel(myChannel);
         RemotingConfiguration.RegisterActivatedClientType(
                                typeof(HelloService),"tcp://localhost:8085/");

         // Get the remote object.
         HelloService myService = new HelloService();

         // Get a sponsor for renewal of time.
         ClientSponsor mySponsor = new ClientSponsor();

         // Register the service with sponsor.
         mySponsor.Register(myService);

         // Set renewaltime.
         mySponsor.RenewalTime = TimeSpan.FromMinutes(2);

         // Renew the lease.
         ILease myLease = (ILease)mySponsor.InitializeLifetimeService();
         TimeSpan myTime = mySponsor.Renewal(myLease);
         Console.WriteLine("Renewed time in minutes is " + myTime.Minutes.ToString());

         // Call the remote method.
         Console.WriteLine(myService.HelloMethod("World"));

         // Unregister the channel.
         mySponsor.Unregister(myService);
         mySponsor.Close();
      }
   }
}