C# MarshallByRefObject变为“;已在服务器上断开连接”;即使是赞助

C# MarshallByRefObject变为“;已在服务器上断开连接”;即使是赞助,c#,debugging,.net-remoting,C#,Debugging,.net Remoting,我正在编写一个支持mods的游戏,为了安全起见,我将mods沙箱化到一个独立于游戏引擎的AppDomain中(这样我就可以独立于引擎限制mods的功能)。但是,脚本域中的对象引擎保留了一个引用,以便过早地收集垃圾,我得到了如下异常: 反对 “/30b08873_4929_48a5_989c_e8e5cebc601f/LHEJBSQ8D8QSGVUULHBKQBO_615.rem” 已断开连接或服务器上不存在 在服务器端,我创建了如下对象(使用: //接受一个“脚本引用”,它基本上只是脚本域中类型

我正在编写一个支持mods的游戏,为了安全起见,我将mods沙箱化到一个独立于游戏引擎的AppDomain中(这样我就可以独立于引擎限制mods的功能)。但是,脚本域中的对象引擎保留了一个引用,以便过早地收集垃圾,我得到了如下异常:

反对 “/30b08873_4929_48a5_989c_e8e5cebc601f/LHEJBSQ8D8QSGVUULHBKQBO_615.rem” 已断开连接或服务器上不存在

在服务器端,我创建了如下对象(使用:

//接受一个“脚本引用”,它基本上只是脚本域中类型的名称
公共引用取消引用(ScriptReference引用),其中T:MarshalByRefObject
{
//创建此类型的远程实例
T instance=(T)RemoteFunc.Invoke(_pluginotext.Domain,reference,r=>
{
var t=Type.GetType(r.TypeName,true,false);
返回Activator.CreateInstance(t);
});
//返回一个引用,该引用使此对象在释放之前保持活动状态
返回新引用(实例,Reference.TypeName,Reference.Name);
}
其思想是引用是对象的发起人,只要它保持活动状态,远程域中的对象也将保持活动状态。这就是问题所在,我通过引用访问对象,但仍然会出现“在服务器上断开连接”异常。以下是我的引用实现:

公共密封类参考
:IDisposable
其中T:MarshallByRefObject
{
私人保荐人(u保荐人),;
公共远程对象
{
获取{return}
}
公共字符串类型名{get;private set;}
公共字符串名称{get;private set;}
公共引用(T obj,字符串类型名称=null,字符串名称=null)
{
TypeName=TypeName;
名称=名称;
_发起人=新的内部发起人(obj);
}
~Reference()
{
如果(_赞助商!=null)
_发起人。处置();
_赞助商=空;
}
公共空间处置()
{
_发起人。处置();
总干事(本);
}
/// 
///内部发起人是实际发起人(由远程处理系统保持活动状态)。
///如果对引用的所有引用都丢失,它将在其析构函数中处理发起方
/// 
私人密封类保险人
:MarshalByRefObject、ISponsor、IDisposable
{
私人只读ILease\u租赁;
私人住宅被出售;
公共只读远程对象;
private bool_isunregisted=false;
公共赞助商(T obj)
{
RemoteObject=obj;
_lease=(ILease)obj.GetLifetimeService();
_lease.Register(this,SponsorTime());
}
公共时间跨度续约(ILease租赁)
{
if(lease==null)
抛出新的异常(“租约”);
如果(_isDisposed)
{
如果(!\u未注册)
{
_租赁。注销(本);
_isUnregistered=true;
}
返回TimeSpan.0;
}
返回时间();
}
专用静态时间跨度赞助商时间()
{
返回TimeSpan.FromMillions(/*从配置中获取的一些值*/);
}
公共空间处置()
{
_isDisposed=true;
}
}
}
我做错了什么,导致我的对象死亡,即使有对它们的实时引用?

使用内置在.NET中的类。它非常稳定且简单


大多数人在跨AppDomains工作时都会使用它。您的实现看起来不错,但可能很简单,就像您的
SponsorTime()
没有从配置中返回正确的值一样。

我在中发现了一种似乎简单得多的解决方案

它包括告诉对象有无限的生命周期,这样做:

[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
  return null;
}

这个解决方案并不一致,但这篇文章给我们带来了更多有价值的答案。

有什么原因吗,你不使用内置的
客户端发起人
?如果
InitializeLifetimeService()也可能是你的AppDomain正在消亡
没有被调用,这将对您的实例造成严重破坏。这只是因为我不知道Client赞助商存在!我假设AppDomainToolkit为我处理调用InitializeLifetimeService的问题,我会检查一下。事实上,我知道AppDomain肯定不会消亡,因为一些远程对象仍在正常工作当其他人断开连接时,我会尝试使用它进行测试,因为它应该是相当简单的实现,并且是大多数人使用的,包括我自己。到目前为止,使用Client赞助商似乎是可行的。显然,考虑到问题的性质和GC在想做什么的时候做什么,很难说!
public sealed class Reference<T>
    : IDisposable
    where T : MarshalByRefObject
{
    private InnerSponsor _sponsor;

    public T RemoteObject
    {
        get { return _sponsor.RemoteObject; }
    }

    public string TypeName { get; private set; }
    public string Name { get; private set; }

    public Reference(T obj, string typeName = null, string name = null)
    {
        TypeName = typeName;
        Name = name;

        _sponsor = new InnerSponsor(obj);
    }

    ~Reference()
    {
        if (_sponsor != null)
            _sponsor.Dispose();
        _sponsor = null;
    }

    public void Dispose()
    {
        _sponsor.Dispose();
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Inner sponsor is the actual sponsor (and is kept alive by the remoting system).
    /// If all references to Reference are lost, it will dispose the sponsor in its destructor
    /// </summary>
    private sealed class InnerSponsor
        : MarshalByRefObject, ISponsor, IDisposable
    {
        private readonly ILease _lease;
        private bool _isDisposed;
        public readonly T RemoteObject;

        private bool _isUnregistered = false;

        public InnerSponsor(T obj)
        {
            RemoteObject = obj;
            _lease = (ILease)obj.GetLifetimeService();
            _lease.Register(this, SponsorTime());
        }

        public TimeSpan Renewal(ILease lease)
        {
            if (lease == null)
                throw new ArgumentNullException("lease");

            if (_isDisposed)
            {
                if (!_isUnregistered)
                {
                    _lease.Unregister(this);
                    _isUnregistered = true;
                }
                return TimeSpan.Zero;
            }

            return SponsorTime();
        }

        private static TimeSpan SponsorTime()
        {
            return TimeSpan.FromMilliseconds(/*Some value fetched from configuration*/);
        }

        public void Dispose()
        {
            _isDisposed = true;
        }
    }
}
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
  return null;
}