2012-04-24 62 views
5

我正在設計一個2個WCF服務,我的所有客戶都會連接到這個服務。其中一項服務將是通知服務。WCF雙工 - 將不同的通知推送給每個客戶端?

我希望每個客戶端連接到服務,訂閱它,然後接收通知,使用雙工回調接口(該服務將觸發客戶端的「通知」操作)。

這是我的設計理念:

enter image description here

我的問題是:當每個客戶端連接到我的服務,我會驗證它針對我的數據庫中「用戶」表(我將使用UserNamePasswordValidator並實現「驗證」功能)。

要求:每個用戶都需要根據數據庫中定義的規則接收不同的通知,但他們都使用相同的合同

例如:

約翰·史密斯的在數據庫中的規則可能是:通知我有超過100美元的價格 所有新產品。

Jane Doe在數據庫中的規則可能是:在所有新產品上通知我,他們的名字以'JA'開頭。

Jim Jabra在數據庫中的規則可能是:通知我所有類型爲「食物」的新產品。

我的服務將有一個工作線程檢測數據庫中的更改(新產品已插入數據庫)。

然後,它應該循環所有連接的客戶端 - 並且每個客戶端都會向他發送新產品通知,只有當它符合客戶端的通知請求時。

再次 - 所有客戶端都會收到相同類型的更新(新產品),但每個客戶端都應根據數據庫中的規則接收不同的產品。

一種方法我想實現,這將是使用辛格爾頓服務,即持有的列表:

  • 客戶Enpoint
  • 用戶對象(從數據庫)

這樣 - 每當工作線程檢測到一個新產品時,它就會遍歷這個列表併發送通知給任何需要它的人。 這種方法的問題是,爲了擁有一個全球客戶名單 - 我需要將這項服務作爲一個Singlton,對嗎?

第二種辦法是......呃......我沒有的我如何可以訪問連接到從工作線程該服務的客戶名單另一個想法...

我猜我的主要問題是每個客戶都可能想要通知他不同種類的產品。含義 - pub \ sub方法在這裏不太好,因爲我的場景需要服務來了解客戶端。

我如何能解決這個頭痛有什麼建議?

+0

你有沒有想過使用隊列。您的每個客戶端都連接到隊列並在可用時輪詢數據。簡單的WCF服務就是訂閱數據的服務。然後在您的工作線程中,當數據與它們相關時,將數據推送到客戶端隊列。 – rpgmaker 2012-04-26 03:52:16

+0

隊列將如何完全解決我的問題?你的意思是'wcf服務是訂閱數據的服務'?你有我可以看的樣品或例子嗎? – 2012-04-26 07:19:09

+0

我的回答是低於 – rpgmaker 2012-04-26 19:34:47

回答

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); 
    } 
} 
+0

所以你說我確實需要一個單獨的服務,並在後臺工作線程注入到它的構造函數的服務? 我不應該做相反的事嗎?將服務注入到後臺工作者的構造函數中? – 2012-04-24 17:21:28

+0

@JohnMiner,不知道你需要什麼後臺工作。我寫了一個小例子。 – 2012-04-24 18:00:58

+0

哇,謝謝你的廣泛的例子!我將嘗試解釋爲什麼我需要一個工作線程。數據庫中有一張表格,其中包含每個用戶的規則 - 他想要哪些產品。 USER1有一條規則,說他希望收到「價格> 50」的產品通知。 USER2有一條規定,他希望收到「價格> 30,價格<70」的產品通知。 USER3有一條規定,他希望名稱中包含「FOOD」的產品。在下一條評論中繼續 – 2012-04-24 20:45:47

0

我的意思是說以下幾點。

創建,將每個客戶端的訂閱過濾器一旦被稱爲WCF服務。 wcf服務本身將簡單地向數據庫添加數據,並在數據存儲中包含客戶端名稱和過濾器信息等信息。然後你的工作者線程將在一個窗口服務中,它將簡單地輪詢你的數據庫的數據,當數據可用時,它將從訂閱表中讀取。然後它會將數據推送到每個客戶端的隊列中,這些客戶端可能是像rabbitmq這樣的共享隊列服務器。

在客戶端假定它是一個基於窗口的應用程序,只需在隊列中用它自己的名字(client1,e.t.c)查找它就可以輪詢rabbitmq隊列服務器的數據。

相關問題