【问题标题】:How to get references to already instantiated remote objects using WCF?如何使用 WCF 获取对已实例化的远程对象的引用?
【发布时间】:2013-11-13 17:59:10
【问题描述】:

我刚刚在 MSDN 网站 (http://msdn.microsoft.com/en-us/library/aa730857(v=vs.80).aspx) 上阅读了 Ingo Rammer 题为“从 .NET Remoting 到 Windows Communication Foundation (WCF)”的文章。

不过,我仍然有一个疑问,希望有人能帮助我。

在会话“第 3 步 - 使用会话而不是客户端激活的对象”中,它准确地涵盖了我们在公司中使用远程处理的类型,他展示了如何获取和使用对在另一端(服务器端)。然而,在我们的例子中,当客户端请求对它们的引用时,我们不会在服务器端实例化这些对象。服务器端已经存在对象(它们之前已实例化),我只想获取对这些已激活对象的引用。

我们今天如何使用远程处理来做到这一点?我们有一个“对象服务器”对象(派生自 MarshalByRefObject)。该对象可通过 URL “tcp://localhost:9002/ObjectServerInstance”获得。远程应用程序可以使用 Activator.GetObject 获取对它的引用。此对象服务器对象实现了一个接口 IObjectServer,该接口声明了一个具有以下签名的方法: 对象GetObject(字符串objTag);

客户端应用程序使用对这个对象服务器对象的引用来调用它的 GetObject 方法,传递一个对象标签字符串作为参数(例如:“组合”)。然后,此方法返回对 Portfolio 对象的引用,该对象先前已使用此标记“Portfolio”在对象服务器对象之前发布自身。 Portfolio 对象当然也派生自 MarshalByRefObject。而且它不是仅在远程客户端请求对其进行引用时才实例化的,它已经在服务器上实例化了。

当然,这可以采取不同的方式。每个可以远程访问的对象都可以通过编程方式使用自己的 objectUri 在服务器端的 Remoting 层之前发布自己(例如:“tcp://localhost:9002/MyObjectInstance”),在客户端我们可以使用 Activator .GetObject 直接获取每个对象的引用。但这与我提出的观点无关。无论如何,当服务器对象在 Remoting 层之前发布时,它们就已经存在了。

我说得够清楚吗?您是否看到了使用 WCF 执行此操作的方法?

【问题讨论】:

  • 服务器端的对象不仅仅在客户端使用。服务器是一个已经在运行的应用程序。服务器上的相同对象可以而且必须被多个客户端访问。例如:我在服务器端反对安全 MSFT(Microsoft)的订单管理器。每个想要为 MSFT 证券发送订单的客户都必须将请求发送给这个订单管理器,在执行一些内部代码之后,这个订单管理器然后将请求的订单发送到适当的交易所(例如:NYSE 或 NASDAQ)。
  • 我无法控制客户端应用何时请求对这些订单管理器对象的引用。唯一的要求是服务器应用程序必须启动,并且当第一个客户端请求引用以发送订单时,必须实例化订单管理器对象。并且所有想要发送 SAME 安全命令的客户端,例如 MSFT,都将在服务器端访问 SAME 对象。

标签: c# wcf migration remoting


【解决方案1】:

查看您提供的链接处的代码,在我看来您需要修改IRemoteFactory 接口的GetInstanceMethod 实现以返回一个现有对象, 而不是创建一个新的。

public interface IRemoteFactory
{
  IMySessionBoundObject GetInstance();
}

public class RemoteFactory : MarshalByRefObject, IRemoteFactory
{
  public IMySessionBoundObject GetInstance()
  {
    // Return an already existing object, instead of a new one.
    return MyAlreadyExistingSessionBoundObject;
  }
}

【讨论】:

  • 如果您使用的是远程处理,那么您是对的。但我的问题是如何使用 WCF 做到这一点。在同一个示例中,当他将代码迁移到 WCF 时,无论如何他使用 ChannelFactory.CreateChannel() 来获取 MySessionBoundObject 对象的新实例。他将 IMySessionBoundObject RemoteFactory.GetInstance() 方法更改为 EndpointAddress10 GetInstanceAddress(),并使用一些技巧来获取对真实对象的引用,但我认为无论如何这些对象在 ChannelFactory.CreateChannel() 时被实例化方法被调用。
  • 您坚持使用预制对象似乎与 WCF 哲学相矛盾,即服务器端的对象只在会话期间存在。 “会话通常不跨越多个服务,而是仅在与单个服务实例的通信中有效。这只是意味着您将在客户端代理的生命周期内与同一个服务器端对象进行对话." 似乎您需要另一个仅在会话生命周期内存在的对象,但知道如何与服务器端预先存在的对象进行通信。
  • 我想我明白你在说什么。我不能将服务器端的持久对象作为我的服务实例。每次客户想要调用我的持久对象的方法时,我都必须创建另一种类型的服务实例。这些服务实例必须知道如何与本地持久对象通信。是这样吗?如果这是正确的,那么使用 Remoting 调用远程持久对象的方法是不是效率更低?使用远程处理我不必每次都创建新的通信通道,该通道保持打开状态。此外,没有中介。
  • 刚刚更新:[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] 属性并不能解决我的问题,主要原因有两个: 1) 再次,我的服务器端持久对象无法在第一次实例化客户端创建一个通道,它们在任何客户端连接之前就已经存在; 2)我的对象不是单例,我可以实例化同一类的多个对象(例如:多个证券的多个投资组合对象)。
【解决方案2】:

您的问题有一个解决方案,但请注意它违反了 WCF 的原则和面向服务的概念。

在服务器上维护会话状态会产生各种后果和潜在的陷阱。您在客户端和服务器之间引入耦合,并且必须仔细考虑在损坏状态和异常的情况下您将做什么。

解决方案对于 Stack Overflow 帖子来说有点太长了,所以我已经将它发布在 github here

我不能为这个解决方案声明任何功劳——其中大部分来自我在某处读过的一篇博文(我会在我记得它是什么后更新它)。有趣的是,它使用了一些相当先进的 WCF 低级代码 - 它非常有助于加深您对 WCF 工作原理的理解。

如果有任何方法避免在生产环境中实现这一点,我会进一步重申。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-26
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    相关资源
    最近更新 更多