【问题标题】:WCF Duplex - Push different notifications to each client?WCF Duplex - 向每个客户端推送不同的通知?
【发布时间】:2012-05-05 02:07:37
【问题描述】:

我正在设计我的所有客户都将连接到的 2 个 WCF 服务。其中一项服务是通知服务。

我希望每个客户端都连接到服务,订阅它,然后使用双工回调接口接收通知(服务将触发客户端中的“通知”操作)。

这是我的设计理念:

我的问题是:当每个客户端连接到我的服务时,我将根据数据库中的“用户”表对其进行验证(我将使用 UserNamePasswordValidator 并实现“验证”功能)。

要求:每个用户需要根据数据库中定义的规则接收不同的通知,但他们都使用相同的合约

例如:

John Smith 在 DB 中的规则可能是:通知我所有有价格的新产品 超过 100 美元。

Jane Doe 在 DB 中的规则可能是:在所有新产品上通知我其名称以“JA”开头。

Jim Jabra 在 DB 中的规则可能是:通知我所有属于“食品”类型的新产品。

我的服务将有一个工作线程来检测数据库中的更改(新产品已插入数据库)。

然后它应该遍历所有连接的客户端 - 并为每个客户端向他发送新产品的通知,前提是它与客户端的通知请求匹配。

同样 - 所有客户端都会收到相同类型的更新(新产品),但每个客户端应根据数据库中的规则接收不同的产品。

我认为实现此功能的一种方法是使用 Singleton 服务,该服务包含以下列表:

  • 客户端端点
  • 用户对象(来自数据库)

这样 - 每次工作线程检测到新产品时,它都会遍历此列表并将通知发送给需要它的人。 这种方法的问题在于,为了拥有一个全球客户列表 - 我需要将服务作为 Singlton,对吗?

第二种方法是......好吧......我不知道如何从工作线程访问连接到服务的客户端列表......

我想我遇到的主要问题是每个客户可能希望将不同种类的产品通知给他。含义 - pub\sub 方法在这里不太好,因为我的场景需要服务了解客户端。

关于如何解决这个头痛的任何建议?

【问题讨论】:

  • 您是否考虑过使用队列。您的每个客户端都连接到队列并轮询可用的数据。并且简单地让 WCF 服务成为订阅数据的服务。然后在您的工作线程中,当数据与它们相关时,将数据推送到客户端队列。
  • 队列如何准确解决我的问题?你是什​​么意思'wcf服务将成为订阅数据的服务'?你有我可以看的样本或例子吗?

标签: wcf push-notification


【解决方案1】:

在使用双工通信的任何方式中,您都需要保持从服务器到客户端打开的 TCP 通道才能发送通知。

客户端是发起与服务器的连接的人,你需要保持这个连接打开,如果这个连接丢失你不能(不应该)发起从服务器到客户端的连接,因为客户端可以在 NAT 之后,有防火墙等。

所以无论如何,服务器端必须有一些静态(单例)对象来保存客户端连接列表,认为这不一定是 WCF 服务。您可以将此对象依赖注入到服务构造函数中。

public class ProductRepository
{
    private EventAggregator eventAggregator;

    public void Add(Product product)
    {
        //...
        eventAggregator.Publish(new NewProductEvent(product))
    }
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class EventPublishingService
{
    private IClientCallback client;
    private EventAggregator eventAggregator;
    private Func<Product, bool> predicate;

    public EventPublishingService(...)
    {
        eventAggregator.Subscibe<NewProductEvent>(OnNewProduct);
    }
    private void OnNewProduct(NewProductEvent e)
    {
        if (predicate(e.Product)==true) client.Notify(e.Product);
    }

    public void Subscribe()
    {
        client = OperationContext.Current.GetCallbackChannel<IClientCallback>()
        var user = ServiceSecurityContext.PrimaryIdentity;
        predicate = GetFilterForUser(user);
    }
}

【讨论】:

  • 所以你是说我确实需要一个单例服务,并将后台工作线程注入到它的构造函数中的服务中?我不应该做相反的事情吗?将服务注入到后台worker的构造函数中?
  • @JohnMiner,不确定您需要什么后台工作人员。我写了一个小例子。
  • 哇,感谢您提供的广泛示例!我将尝试解释为什么我需要一个工作线程。数据库中有一个表,其中包含每个用户的规则——他想要哪些产品。 USER1 有一条规则,表示他希望收到有关“价格 > 50”的产品的通知。 USER2 有一条规则,表示他希望收到“价格 > 30 且价格
  • 我将有一个后台工作人员等待数据库中“产品”表中的新事件事件(可能使用 SqlDependency)。当一个新产品被添加到表中时(通过一些外部服务) - 工作线程将检测到这一点 - 并检查哪些用户希望收到有关该产品的通知。如果产品价格为 58,则需要通知 USER1 和 USER2 关于此新产品。所以后台线程现在将检查已连接客户端的列表 - 并检查它们中的任何一个是 USER1 还是 USER2。如果是这样 - 它会向他们发送有关此新产品的通知。
  • 所以你明白我为什么需要后台工作线程了吗? (我已经稍微简化了我的需求,但这基本上就是我所需要的)。我不确定需要什么“存储库”以及什么是“EventAggregator”。根据我在之前的 cmets 中写的 - 你的代码示例仍然是我需要的吗?
【解决方案2】:

我想说的是以下内容。

创建一个 wcf 服务,每个客户端都会调用该服务来订阅过滤器一次。 wcf 服务本身将简单地将数据添加到数据库中,并在数据存储中包含客户端名称和过滤器信息等信息。然后,您的工作线程将位于窗口服务中,该服务将简单地轮询您的数据库以获取数据,当数据可用时,它将从订阅表中读取。然后它将数据推送到每个客户端的队列,这可能是一个共享队列服务器,如rabbitmq。

在客户端假设它是一个基于窗口的应用程序,它会简单地通过在队列中以自身名称(client1,e.t.c)查找它来轮询 rabbitmq 队列服务器以获取它的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多