47

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

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

目标对象还活着,我已经检查过了。

UPD 我在目标对象的终结器中设置了断点,它永远不会命中。因此,这个对象是活着的并且没有被 GC 处理。

4

7 回答 7

34

那可能是因为服务器端的本地垃圾收集器收集了对象。您可以通过更新租约来防止这种情况发生。您可以在以下文章中阅读更多相关信息:

更新:不幸的是,2008 年或更早的 MSDN 杂志问题不再可在线浏览,而只能作为 .chm 文件下载到本地计算机。以前的问题可以在以下位置找到:

于 2011-06-14T06:07:51.760 回答
15

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

于 2011-09-22T13:01:18.123 回答
4

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

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

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

这是完整的解释和用例:

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

/// <see cref="https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called"/>
public class RemotingSponsor : MarshalByRefObject, ISponsor, IDisposable
{
    /*
     * @CoryNelson said :
     * I've since determined that the ILease objects of my sponsors 
     * themselves are being GCed. They start out with the default 5min lease 
     * time, which explains how often my sponsors are being called. When I 
     * set my InitialLeaseTime to 1min, the ILease objects are continually        
     * renewed due to their RenewOnCallTime being the default of 2min.
     * 
     */ 

    ILease _lease;

    public RemotingSponsor(MarshalByRefObject mbro)
    {
        _lease = (ILease)RemotingServices.GetLifetimeService(mbro);
        if (_lease == null) throw new NotSupportedException("Lease instance for MarshalByRefObject is NULL");
        _lease.Register(this);
    }

    public TimeSpan Renewal(ILease lease)
    {
        Debug.WriteLine("RemotingSponsor.Renewal called");
        return this._lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;
    }


    public void Dispose()
    {
        if (_lease != null)
        {
            _lease.Unregister(this);
            _lease = null;
        }
    }

    public override object InitializeLifetimeService()
    {
        /*
         *
         * @MatthewLee said:
         *   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. 
         * The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease. 
         * It's created in your Client domain and your Host domain has a proxy to the reference in your Client domain. 
         * 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.
         *   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.
         * Source: https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called
        */
        return (null);
    }
}

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

// Loader and Container for MarshalByRefObject in another domain
 public class PluginFile : IDisposable
 {
           private RemotingSponsor _sponsor; // Keep instance not to have Sponsor Garbage Collected
           private AppDomain _sandbox;
           private ICustomPlugin[] _plugins; // I do not store real instances of Plugins, but a "CustomPluginProxy" which is known both by main AppDomain and Plugin AppDomain.

    // Constructor : load an assembly file in another AppDomain (sandbox)
    public PluginFile(System.IO.FileInfo f, AppDomainSetup appDomainSetup, Evidence evidence)
    {
        Directory = System.IO.Path.GetDirectoryName(f.FullName) + @"\";
        _sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup);

        _sandbox.Load(typeof(Loader).Assembly.FullName);

        // - Instanciate class "Loader" INSIDE OTHER APPDOMAIN, so we couldn't use new() which would create in main AppDomain.
        _loader = (Loader)Activator.CreateInstance(
            _sandbox,
            typeof(Loader).Assembly.FullName,
            typeof(Loader).FullName,
            false,
            BindingFlags.Public | BindingFlags.Instance,
            null,
            null,
            null,
            null).Unwrap();

        // - Load plugins list for assembly
        _plugins= _loader.LoadPlugins(f.FullName); 


        // - 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.
        // - Here is an explanation. Source: https://stackoverflow.com/questions/12306497/how-do-the-isponsor-and-ilease-interfaces-work
        _sponsor = new RemotingSponsor(_loader);

       // Here is my SOLUTION after many hours ! I had to sponsor each MarshalByRefObject (plugins) and not only the main one that contains others !!!
       foreach (ICustomPlugin plugin in Plugins) 
        {
            ILease lease = (ILease)RemotingServices.GetLifetimeService((PluginProxy)plugin);
            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.
        }
    }

 }

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

 /// <see cref="https://stackoverflow.com/questions/4185816/how-to-pass-an-unknown-type-between-two-net-appdomains"/>
    [Serializable]
    public class PluginProxy : MarshalByRefObject, ICustomPlugin
    {
        private ICustomPlugin _hostedPlugin;            

        /// <summary>
        /// Parameterless constructor for deserialization 
        /// </summary>
        public PluginProxy()
        {             
        }

        ~PluginProxy()
        {
            Debug.WriteLine("DESTRUCTOR ~PluginProxy");
        }

        /// <summary>
        /// Constructor reserved from real Plugin type
        /// </summary>
        /// <param name="name"></param>
        public PluginProxy(ICustomPlugin hostedPlugin)
        {
            _hostedPlugin = hostedPlugin;
        }

        public PluginName Name => _hostedPlugin.Name;

        public PluginResult Execute(PluginParameters parameters, PluginQuery query)
        {
            return(_hostedPlugin.Execute(parameters, query));
        }
    }

这是一堆很难解决的问题,希望这有帮助!

参考:

于 2018-03-29T08:59:52.443 回答
3

这发生在我们身上,因为我们的一个类中有一个 AppDomain 类型的静态变量。该类用于长期运行的 Windows 服务。AppDomain 有一个 InitializeLifetimeService 方法,需要像这样重写:

public override object InitializeLifetimeService(){
    return null;
}

我们一直使用它作为私有变量,为自定义构建的外部逻辑加载和卸载一些 dll。答案取自这里:msdn answer

因为我们无法在生产时更改这一点,所以我们以比静态 AppDomain 变量的生命周期更短的随机间隔重新启动 Windows 服务结束,通过反复试验,我们发现它是几天。

这个问题也有助于澄清一些关于生命周期的事情:stackoverflow-question

于 2018-12-11T16:16:44.513 回答
3

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

  1. 如果您希望 Singleton 语义覆盖InitializeLifetimeService返回 null
  2. 用于ClientSponsor让您的对象存活更长时间。
于 2019-01-27T17:37:10.193 回答
0

就我而言,问题是在客户端计算机中,有一个虚拟网络适配器处于活动状态,禁用虚拟网络适配器,问题就解决了

于 2013-11-18T19:57:04.333 回答
0

就我而言,这发生在存储在项目App_Data内文件夹中的 SQL LocalDB 上Web。每当我尝试使用包控制台运行update-database以使用迁移来初始化我的实体框架数据库时,什么都没有发生。然后过了一会儿,我得到了那个错误。

我通过修改App_Data. 一旦修复,瞧,它工作。

于 2016-05-28T00:18:11.903 回答