【问题标题】:How does one set up a WCF ServiceHost within a Windows Service that can access stateful information within the Windows Service如何在 Windows 服务中设置可以访问 Windows 服务中的状态信息的 WCF ServiceHost
【发布时间】:2010-11-19 15:54:15
【问题描述】:

我用 C# 编写了一个 Windows 服务。它运行良好并且表现良好。我在 Windows 服务中添加了 WCF 服务,以使客户端应用程序能够连接到 Windows 服务并从 Windows 服务获取状态信息。

我将 WCF 服务配置为单例,以便使用同一个服务实例来处理来自所有客户端的所有请求,如下所示:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

所有客户端都能够连接并访问 WCF 服务中的相同状态信息。但是,我遇到了以下特殊行为。

修订:
我在我的 Windows 服务中实例化 WCF 服务合同。在实例化时分配的任何状态信息都可供连接到服务的所有客户端使用。

但是,稍后直接从​​ Windows 服务(而不是客户端)添加到 服务合同 实例的任何状态信息对于连接到该服务的客户端是不可见的。就好像服务契约有两个实例:一个用于 Windows 服务,一个用于连接到 WCF 服务的客户端。

实例化 WCF 服务并使其能够访问 Windows 服务中可用的状态信息的推荐(最佳)方法是什么?

【问题讨论】:

    标签: c# wcf windows-services servicehost stateful


    【解决方案1】:

    设置 InstanceContextMode.Single 将导致 ServiceHost 构造您的服务的单个实例并将其用于所有调用。但是听起来您想自己构建实例,并使用对某些共享状态的引用来填充它。如果是这样,这称为“知名实例”模式,可以通过将实例传递给 ServiceHost 构造函数来完成,如下所示:

    var svc = new MyServiceClass(state);
    var host = new ServiceHost(svc, new Uri(..), ...);
    ...
    

    ServiceHost 将使用您传入的实例进行所有调用。

    使用单实例模式(无论对象是“众所周知的”还是由 ServiceHost 构造的)时,一个重要的考虑因素是线程。默认情况下,WCF 将只允许一个线程同时执行每个服务实例。因此在 PerCall 实例模式下,由于您将拥有多个服务实例,因此您可以支持多个并发线程,这将提高正常情况下的吞吐量。但是在单实例模式下,您只有一个服务实例,因此您一次只能运行一个线程。这取决于服务,但通常将并发模式切换为 Multiple 是有意义的,这将允许多个并发线程进入您的服务实例,但要求您的服务实现是线程安全的。

    这里有一些不错的文档:http://msdn.microsoft.com/en-us/library/ms731193.aspx

    【讨论】:

      【解决方案2】:

      为什么 WCF 服务必须有状态信息?难道不能将其存储在数据库中并在需要时访问吗?

      WCF 确实允许服务的 Singleton 实例 - 但通常不鼓励使用此实例,除非您绝对必须这样做。通常,如果您可以将有状态信息存储在例如,它会更容易并且可以更好地扩展。一个数据库表,并让客户端使用普通的每次调用 WCF 服务来访问它。

      更新:
      好的,另一个想法:无论如何,您将永远只有一个 ServiceHost。如果您选择“每次调用”实例化模式(如所有领先专家的建议),ServiceHost 将分配一个工作线程线程池,然后为传入的请求提供服务。

      为什么 WCF 服务需要是单例的?难道你不能使用“per-call”并仍然获得 NT 服务中的状态信息吗?

      一个请求进来,你的服务对象(服务类,实现服务接口)的实例被创建。您现在如何访问 NT 服务中的状态信息?难道你不能在新创建的服务实例中也这样做——当你真正需要它的时候?

      如果您在 NT 服务中保存有状态信息,则需要确保正确处理任何并发访问 - 这完全与您的 WCF 服务类是否为单例无关。

      更新 2:
      使用“OperationContext.Current.Host”,您可以访问在正在执行的服务方法内托管给定服务实例的 ServiceHost - 不确定您是否可以访问实际的 NT 服务实例。但是,如果您创建自己的自定义 ServiceHost 后代,它有一个附加属性“ListOfClients”,您应该能够随时从任何正在运行的服务实例访问该列表。

      请注意:由于在任何给定时间可能有任意数量的服务请求正在处理,读取列表必须是线程安全的,并且从 Windows NT 服务更新列表更加“有风险”,需要考虑这些并发问题!如果您需要更新列表,请锁定它 - 否则,您将获得不可预知的结果。

      马克

      【讨论】:

      • 我真的不需要 WCF 服务是有状态的。我已经在 Windows 服务中有状态信息。我希望 WCF 服务能够将这些信息提供给请求它的客户端。我该如何解决这个问题?
      • 当然,我可以通过将信息存储到数据库来解决这个问题。当信息已经在 Windows 服务中可用时,这似乎是不必要的开销,尤其是当 WCF 服务托管在 Windows 服务的上下文中时。看来我现在不必额外存储它并从数据库中检索它以使其可供客户访问。理想情况下,我希望 WCF 服务提供对 Windows 服务中的有状态数据的访问。
      • 为了回答您的问题,我最初开始将列表的引用分配给 WCF 服务主机实例,但现在将放弃这种方法,因为除了需要 Singleton 之外它不起作用。
      • 我明白了。我计划使用“每次通话”,因为我同意这是一种更好的方法。我基本上有一个发现服务器的客户端的状态列表。如果我在 WCF 服务可以访问的 Windows 服务中将此 List 设为静态会怎样?
      • Elan:我认为您在这里有一个误解:ServiceHost 实例只会作为单个实例存在 - 开始时只有 ONE!这不是您使用 InstanceContextMode 设置控制的内容。
      【解决方案3】:

      我建议通过将状态保存在静态成员中来解决此问题,以便 WCF 是为每个调用创建一个新实例还是重用一个实例都无关紧要。这样就解决了问题,简化了代码。

      【讨论】:

        猜你喜欢
        • 2011-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-13
        • 1970-01-01
        相关资源
        最近更新 更多