2

我有一个 WCF 服务,所有客户端都连接到该服务以获取通知\提醒(使用他们实现的 CALLBACK 接口)。目前 WCF 服务是自托管的,但计划是将其托管在 Windows 服务中。

WCF 服务具有“发布”、“订阅”和“取消订阅”操作。

我需要有某种后台工作线程[每 XXX 分钟] 不断地轮询 SQL 服务器数据库表,并查找某些“提醒”行。一旦找到它们 - 它应该通知所有连接的客户端。

我想到了两种方法来实现这一点。

.

方法一:

有一个单独的 EXE 项目(不希望它成为控制台,那么它应该是什么 - Windows 服务?)将启动并运行后台线程。后台线程将作为其客户端之一连接到“提醒”服务。后台线程将轮询数据库,一旦它找到一些东西 - 它会向 WCF 服务发送一条“发布”消息,这将使 WCF 服务向所有订阅的客户端发送提醒。

.

方法乙:

以某种方式使后台线程WCF 服务项目中运行,当它在数据库中检测到新的提醒行时,以某种方式使其向 WCF 服务“发出信号”,然后 WCF 服务将把该信息发送给所有订阅的客户端.

.

哪种方法更好?还有其他建议吗?

4

2 回答 2

6

如果这是一个长期运行的过程,Windows 服务是完美的解决方案。您的主 Win 服务线程将轮询数据库,将结果排队到某种供应商/消费者线程安全集合中。

您可以在 win 服务中托管 WCF 服务,然后该服务可以使用(删除)队列中的任何结果并根据请求将它们传递回客户端(对 WCF 的调用将进入它们自己的线程)

这是一个非常常见的架构,并且不难实现。

于 2012-06-30T13:38:40.733 回答
1

方法一:

如果您要创建两个单独的主机(即,一个用于 WCF 服务,一个用于“轮询”服务),那么您实际上只有一个选项可以让它们正常工作。

Windows 服务通信非常有限(没有服务端点的帮助,例如 WCF)。因此,如果您要在 Windows 服务中托管“轮询”服务,则无论如何都必须将其与 WCF 服务相结合。

然后将这两个服务一起托管在一个 Windows 服务中并通过手动实例化 WCF 主机并将“轮询”服务传递给构造函数是可行的。

protected override void OnStart(string[] args)
{
    //...

    // This would be you "polling" service that would start a background thread to poll the db.
    var notificationHost = new PollingService();
    // This is your WCF service which you will be "self hosted".
    var serviceHost = new WcfService(notificationHost);

    new ServiceHost(serviceHost).Open();
    //...
}

这远非理想,因为您需要通过两个服务之间的事件进行通信,而且您的 WCF 服务必须在单例模式下运行才能手动实例化工作......所以这让你......

方法B:

如果您要在 WCF 服务中托管“轮询”服务,您将遇到许多问题。

  1. 您需要了解创建的“轮询”服务实例的数量。如果您的 WCF 服务已配置为为每个会话实例化,您可能会得到太多的“轮询”服务,而这最终可能会杀死您的数据库/服务器。
  2. 为避免第一个问题,您可能需要设置单例 WCF 服务,这可能会在不久的将来导致扩展问题,即一个 WCF 服务实例不足以处理连接请求的数量。

方法C:

鉴于方法 A 和 B 的缺点,最好的解决方案是托管两个独立的 WCF 服务。

  1. 这是您订阅/取消订阅/发布的常规服务。
  2. 这是您的带有订阅/取消订阅的轮询单例服务。

这个想法是,您的常规服务在收到订阅者后将打开与您的轮询服务的新连接或使用现有连接(取决于您如何配置会话)并等待回复。您的轮询服务是一项长期运行的 WCF 服务,它轮询您的数据库并将通知发布给其订阅者(即其他 WCF 主机)。

优点:

  1. 您可以放心,只有一项投票服务。
  2. 您可以扩展您的解决方案以在 IIS 中托管常规服务并在 Windows 服务中托管轮询服务。
  3. 两个服务之间的通信限制最小,并且不需要事件。
  4. 通过它们的接口相互依赖地测试每个服务。
  5. 服务之间的低耦合和高内聚(这就是我们想要的!)。

缺点:

  1. 更多的服务意味着更多的接口和合约需要维护。
  2. 更高的复杂性。
于 2013-01-29T02:10:06.943 回答