"对象已断开连接或在服务器上不存在"异常

use*_*528 42 .net c# clr appdomain marshalbyrefobject

我需要在我的应用程序中使用跨appdomain调用,有时我有这个RemotingException:

对象'/2fa53226_da41_42ba_b185_ec7d9c454712/ygiw+xfegmkhdinj7g2kpkhc_7.rem'已断开连接或在服务器上不存在.

目标对象仍然存在,我已经检查过了.

UPD我在目标对象的终结器中设置断点,它永远不会命中.因此,这个对象是活着的,而不是GC.

Mar*_*ila 33

这可能是因为服务器端的本地垃圾收集器收集了该对象.您可以通过续订租赁来防止这种情况.您可以在这些文章中阅读更多相关信息:

更新:不幸的是,从2008年或更旧的MSDN杂志的问题不再是浏览的网上,但仅作为,你必须下载到本地机器.chm文件.以前的问题可以在以下位置找到:

  • 在*Server*端,您可以调用RemotingServices.Disconnect(myObject); (2认同)
  • @ user626528引用死了吗?什么时候 ?你的意思是不改变一生?如果是这样,那是因为如果客户端在一段时间内没有调用任何方法,默认的Remoting会自动断开它并释放它的引用. (2认同)

Ste*_*ack 15

这是因为服务器端的Lifetime管理在其租约到期时断开对象,以允许GC收集它.如果您尝试从客户端使用它,您将获得一个例外,即使它尚未在服务器上进行GC(例如因为还有另一个引用)但租约已过期.这是为了避免不可预测的行为.接受的答案为如何正确管理远程.NET对象的生命周期提供了很好的参考.


Elo*_*Elo 7

我遇到了同样的问题,并且在许多 StackOverflow 帖子的帮助下搜索了很多个小时。

\n\n

我终于找到了完整的问题。

\n\n
    \n
  1. 我必须使用赞助商来维持我的 MarshalByRefObject 的活动。
  2. \n
  3. 然后我遇到了与 @user626528 相同的问题:对象还活着,但我有例外。事实上,我需要“赞助”所有“ TransparentProxy ”实例,而不仅仅是主要实例:我在 SandBox(另一个 AppDomain)中创建的主对象返回对其他 MarshalByRefObjects 的引用。
  4. \n
\n\n

这是完整的解释和用例:

\n\n

我的“Loader”类继承自 MarshalByRefObject,并通过 ISponsor 类使其保持活动状态。我知道 .NET 中存在“ClientSponsor”,但我无法确定是否以及何时调用 Renewal(),因此我在 StackOverflow 社区的帮助下创建了我的类(阅读代码注释):

\n\n
/// <see cref="/sf/ask/1307646511/"/>\npublic class RemotingSponsor : MarshalByRefObject, ISponsor, IDisposable\n{\n    /*\n     * @CoryNelson said :\n     * I\'ve since determined that the ILease objects of my sponsors \n     * themselves are being GCed. They start out with the default 5min lease \n     * time, which explains how often my sponsors are being called. When I \n     * set my InitialLeaseTime to 1min, the ILease objects are continually        \n     * renewed due to their RenewOnCallTime being the default of 2min.\n     * \n     */ \n\n    ILease _lease;\n\n    public RemotingSponsor(MarshalByRefObject mbro)\n    {\n        _lease = (ILease)RemotingServices.GetLifetimeService(mbro);\n        if (_lease == null) throw new NotSupportedException("Lease instance for MarshalByRefObject is NULL");\n        _lease.Register(this);\n    }\n\n    public TimeSpan Renewal(ILease lease)\n    {\n        Debug.WriteLine("RemotingSponsor.Renewal called");\n        return this._lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;\n    }\n\n\n    public void Dispose()\n    {\n        if (_lease != null)\n        {\n            _lease.Unregister(this);\n            _lease = null;\n        }\n    }\n\n    public override object InitializeLifetimeService()\n    {\n        /*\n         *\n         * @MatthewLee said:\n         *   It\'s been a long time since this question was asked, but I ran into this today and after a couple hours, I figured it out. \n         * The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease. \n         * It\'s created in your Client domain and your Host domain has a proxy to the reference in your Client domain. \n         * This expires after the default 5 minutes unless you override the InitializeLifetimeService() method in your Sponsor class or this sponsor has its own sponsor keeping it from expiring.\n         *   Funnily enough, I overcame this by returning Null in the sponsor\'s InitializeLifetimeService() override to give it an infinite timespan lease, and I created my ISponsor implementation to remove that in a Host MBRO.\n         * Source: /sf/ask/1307646511/\n        */\n        return (null);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我像这样使用这个“自定义赞助商”:

\n\n
// Loader and Container for MarshalByRefObject in another domain\n public class PluginFile : IDisposable\n {\n           private RemotingSponsor _sponsor; // Keep instance not to have Sponsor Garbage Collected\n           private AppDomain _sandbox;\n           private ICustomPlugin[] _plugins; // I do not store real instances of Plugins, but a "CustomPluginProxy" which is known both by main AppDomain and Plugin AppDomain.\n\n    // Constructor : load an assembly file in another AppDomain (sandbox)\n    public PluginFile(System.IO.FileInfo f, AppDomainSetup appDomainSetup, Evidence evidence)\n    {\n        Directory = System.IO.Path.GetDirectoryName(f.FullName) + @"\\";\n        _sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup);\n\n        _sandbox.Load(typeof(Loader).Assembly.FullName);\n\n        // - Instanciate class "Loader" INSIDE OTHER APPDOMAIN, so we couldn\'t use new() which would create in main AppDomain.\n        _loader = (Loader)Activator.CreateInstance(\n            _sandbox,\n            typeof(Loader).Assembly.FullName,\n            typeof(Loader).FullName,\n            false,\n            BindingFlags.Public | BindingFlags.Instance,\n            null,\n            null,\n            null,\n            null).Unwrap();\n\n        // - Load plugins list for assembly\n        _plugins= _loader.LoadPlugins(f.FullName); \n\n\n        // - Keep object created in other AppDomain not to be "Garbage Collected". I create a sponsor. The sponsor in registed for object "Lease". The LeaseManager will check lease expiration, and call sponsor. Sponsor can decide to renew lease. I not renewed, the object is garbage collected.\n        // - Here is an explanation. Source: /sf/ask/861454821/\n        _sponsor = new RemotingSponsor(_loader);\n\n       // Here is my SOLUTION after many hours ! I had to sponsor each MarshalByRefObject (plugins) and not only the main one that contains others !!!\n       foreach (ICustomPlugin plugin in Plugins) \n        {\n            ILease lease = (ILease)RemotingServices.GetLifetimeService((PluginProxy)plugin);\n            lease.Register(_sponsor); // Use the same sponsor. Each Object lease could have as many sponsors as needed, and each sponsor could be registered in many Leases.\n        }\n    }\n\n }\n
Run Code Online (Sandbox Code Playgroud)\n\n

PluginProxy 类型具有对真实插件类型的引用。事实上,PluginProxy 在 Plugin AppDomain 中实例化,并返回到主 AppDomain,以允许它调用插件,即使它忽略插件的真实类型。因此,要从主 AppDomain 访问 PluginProxy,必须进行序列化以跨越 AppDomain 限制。我遇到了问题,因为我没有赞助这些 MarshalByRefObject(s) :

\n\n
 /// <see cref="/sf/ask/293007151/"/>\n    [Serializable]\n    public class PluginProxy : MarshalByRefObject, ICustomPlugin\n    {\n        private ICustomPlugin _hostedPlugin;            \n\n        /// <summary>\n        /// Parameterless constructor for deserialization \n        /// </summary>\n        public PluginProxy()\n        {             \n        }\n\n        ~PluginProxy()\n        {\n            Debug.WriteLine("DESTRUCTOR ~PluginProxy");\n        }\n\n        /// <summary>\n        /// Constructor reserved from real Plugin type\n        /// </summary>\n        /// <param name="name"></param>\n        public PluginProxy(ICustomPlugin hostedPlugin)\n        {\n            _hostedPlugin = hostedPlugin;\n        }\n\n        public PluginName Name => _hostedPlugin.Name;\n\n        public PluginResult Execute(PluginParameters parameters, PluginQuery query)\n        {\n            return(_hostedPlugin.Execute(parameters, query));\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一个很难解决的问题,希望这对您有所帮助!

\n\n

参考:

\n\n\n

  • CleientSponsor 实现 https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/runtime/remoting/clientsponsor.cs (2认同)

cdi*_*ins 5

这个问题已经在 StackOverflow 上得到了非常详细的回答。TL/DR:

  1. 如果您希望 Singleton 语义覆盖InitializeLifetimeService返回 null
  2. 用于ClientSponsor使您的对象存活更长时间。