MarshalByRefObject在服务器上“断开连接”;即使是赞助的时候

本文关键字:即使是 断开连接 服务器 连接 断开 MarshalByRefObject | 更新日期: 2023-09-27 17:52:56

我正在编写一款支持mods的游戏,为了安全起见,我将mods放入了一个独立于游戏引擎的AppDomain中(所以我可以将mods的功能与引擎分开限制)。然而,在脚本领域的对象,引擎保持引用保持垃圾收集太早,我得到这样的一个异常:

对象'/30 b08873_4929_48a5_989c_e8e5cebc601f/lhejbssq8d8qsgvuulhbkqbo_615.rem '已断开连接或服务器上不存在。

在服务器端,我创建这样的对象(使用AppDomainToolkit:

)
// Take in a "script reference" which is basically just the name of a type in the scripting domain
public Reference<T> Dereference<T>(ScriptReference reference) where T : MarshalByRefObject
{
    // Create a remote instance of this type
    T instance = (T)RemoteFunc.Invoke<ScriptReference, object>(_pluginContext.Domain, reference, r =>
    {
        var t = Type.GetType(r.TypeName, true, false);
        return Activator.CreateInstance(t);
    });
    //Return a reference which keeps this object alive until disposed
    return new Reference<T>(instance, reference.TypeName, reference.Name);
}
这个想法是,Reference是对象的赞助者,只要它保持活动状态,远程域中的对象也将保持活动状态。这就是问题所在,我通过它们的引用访问对象,但我仍然得到"服务器断开连接"异常。下面是我对Reference: 的实现
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;
        }
    }
}

我做错了什么,导致我的对象死亡,即使有一个活的引用给他们?

MarshalByRefObject在服务器上“断开连接”;即使是赞助的时候

使用。net内置的ClientSponsor类。它非常稳定和简单。

这是大多数人在跨应用域工作时转向的。您的实现看起来很好,但可能像您的SponsorTime()没有从配置返回正确的值一样简单。

我在这个StackOverflow帖子中发现了一个似乎更简单的解决方案。

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

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

这个解决方案并不是一致的,但是这个帖子给我们带来了很多有价值的答案。