【问题标题】:How to make WCF Service with a background worker thread?如何使用后台工作线程制作 WCF 服务?
【发布时间】:2012-07-01 17:31:44
【问题描述】:

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

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

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

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

.

方法一:

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

.

方法 B:

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

.

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

【问题讨论】:

    标签: wcf backgroundworker


    【解决方案1】:

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

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

    这是一种非常常见的架构,实施起来并不难。

    【讨论】:

    • 可以使用 Couchbase 或 AppFabric 等高性能缓存系统来存储排队的数据。这样,数据就不会不稳定。
    • 如何让 WCF 服务“使用”队列中的结果?这表明 WCF 服务本身应该有某种轮询队列的工作线程......你有任何示例\示例代码给我吗? (你说这是通用架构)
    • @Erix - 你有答案吗?
    • @JohnMiner wcf 服务中没有工作线程。该服务可能包含一个接口和实现类,它们是您的 Windows 服务项目的一部分,因此它们可以像任何其他类一样访问数据。服务代码在客户端调用并请求他们的通知之前不会运行,您可以将其从主 Windows 服务线程填充的队列中删除并返回给客户端。
    • @Erix - 这不是我需要的。我需要 WCF 服务以某种方式“知道”客户端何时发生事件 - 当发生这种情况时,立即将此事件发布给相关客户端。客户端不轮询 WCF 服务。他们只是连接到它以接收通知。一个不同的线程正在努力找出是否有任何新的通知要发送(这是由一个工作线程每 30 分钟完成一次) - 如果这个工作线程发现有新的通知 - 它需要告诉 WCF通知客户的服务。那么如何做到这一点呢?
    【解决方案2】:

    方法一:

    如果您要创建两个单独的主机(即,一个用于 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. 更高的复杂性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多