5

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

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

这是我的设计理念:

在此处输入图像描述

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

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

例如:

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

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

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

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

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

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

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

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

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

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

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

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

4

2 回答 2

2

无论如何,对于双工通信,您需要保持从服务器到客户端打开的 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);
    }
}
于 2012-04-24T13:40:36.953 回答
0

我想说的是以下内容。

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

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

于 2012-04-26T19:34:32.297 回答