为什么我的C#Remoting对象超时,即使Lifetime返回null?

时间:2011-05-26 02:35:31

标签: c# .net events windows-services remoting

这是谷歌搜索试图找到我的问题的确切答案后的最后一招。

我创建了一个Windows服务,一个Windows窗体和一个Remoting对象(所有这些都在C#中)。我正在使用Remoting对象使用事件在服务和表单之间进行通信。

以下是对象之间典型交互的简化示例:

  • AdminForm 调用 RemoteObject的方法RequestLoadForm()
  • RemoteObject 会触发一个事件, AdminService 正在侦听
  • AdminService 会收到有关该事件的警报,并在 RemoteObject
  • 上调用LoadFormData(字符串数据)
  • RemoteObject 会触发一个事件, AdminForm 正在侦听
  • AdminForm 会收到有关该事件的提醒,并可以使用字符串数据在 AdminForm 的控件上设置值

这一切都很好,一切都在前5分钟内完美地相互作用。之后,对象之间的连接以某种方式被切断,我无法再在对象之间进行通信。

首先解决问题的方法是覆盖InitializeLifetimeService方法以返回null。这没有用(虽然它可以避免任何未来的租赁问题)。

第二次尝试是使我的 AdminForm AdminService RemoteObject 的ISponsors,并将它们设置为续订对象的租约。再一次,没有解决问题。

在我的各种谷歌搜索中,我发现有人提到有关垃圾收集事件处理程序的事情。我不确定这是不是问题,但我想我会提到它。

这是连接空闲后为>弹出的错误。 5分钟:

System.Runtime.Remoting.RemotingException未被用户代码
处理   消息=“未找到请求的服务”
  源= “System.Runtime.Remoting”

现在,关于这一点的奇怪之处在于它出现在 AdminService 方面。 AdminForm 调用 RemoteObject 上的方法。这会弹出事件,然后 AdminService 会看到此事件,并尝试调用 RemoteObject 的方法LoadFormData(字符串数据),这就是抛出异常的地方

我完全厌倦了谷歌搜索,因为我似乎找不到我需要解决的问题。

5 个答案:

答案 0 :(得分:3)

我面临着相当类似的问题。希望以下观察和解决方案也适合任何有类似问题的人。

让对象A跨应用程序域与对象B通信,而对象B将通过某些事件处理程序回调对象A.对象A和B都继承自MarshalByRefObject,以启用跨应用程序域的相互调用。

对象B覆盖InitializeLifeTimeService,以便为无限租约返回null。但是,在程序启动后,连接仍将过期约5分钟(远程默认初始租约时间)。

一个重要的观察是来自对象A的调用仍然会成功执行,但是当对象B回调时,对象B上会引发异常。显然,对象A的回调代理发生了连接到期,而不是我们认为是相反的。

因此,快速回答,确保对象A和B都覆盖InitializeLifeTimeService以返回null。这将解决问题,至少在我的情况下。

只是一些额外的东西,当连接过期时,它并不意味着连接对象被垃圾收集。租约到期将导致代理断开连接,但实际对象仍可能出现在相应的应用程序域中。如果您将对象保持等于GC的对象,那么它可能会使您无法看到整个图片。

答案 1 :(得分:2)

应该覆盖:

public override object InitializeLifetimeService(){
  return null;
}

答案 2 :(得分:1)

您可以在服务器端的System.Runtime.Remoting.Lifetime.LifetimeServices中设置静态属性:

System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseTime = TimeSpan.MaxValue;

但我更喜欢使用租约/赞助商(在客户端)

http://msdn.microsoft.com/en-us/library/6tkeax11.aspx

MarshalByRefObject obj = remotingObject as MarshalByRefObject;
ILease lease = (ILease)obj.GetLifetimeService();
MyClientSponsor sponsor = new MySponsor();
lease.Register(sponsor);

如果您在编组时遇到任何其他问题,请使用System.Runtime.Remoting.Services.TrackingServices命名空间 http://msdn.microsoft.com/en-us/library/system.runtime.remoting.services.trackingservices.aspx

答案 3 :(得分:0)

您应该覆盖方法InitializeLifeTimeService()而不是GetLifetimeService()以返回null。

 public object InitializeLifetimeService(){
   return null;
 }

然后删除对象应该有无限的生命周期。

答案 4 :(得分:0)

这可能有几个原因。

  • 您可能会在错误的对象上覆盖InitializeLifetimeService。在源代码中搜索MarshalByRef的所有提及内容,并给予每个提及一个长期,艰难的外观。

  • 无限租约仅持续到卸载应用程序域。在源代码中搜索Unload的所有提及,并给每个卸载任何AppDomain的内容一个长期,难以查看的内容。

  • AppDomain可能已重新加载进程终止,例如Win32服务重新启动。如果您的服务器部署到某种应用程序服务器并且某些部署操作或错误恢复触发重新加载,它也可能被第三方代码卸载;检查第三方日志以找到证据。

  • 添加足够的日志记录,并仔细研究异常堆栈跟踪,以确保您没有调用第三方服务器对象(可能通过您自己的无限租用服务器对象),或旧版本你知道在哪里加载自己的代码,以便上面的源代码研究可能会错过它。

我刚刚完成了对事件的研究,该事件原本是我名单上第一个和最后一个项目的组合。