2012-10-01 87 views
1

我有一個自我託管的WCF服務,我在Silverlight應用程序中使用。我正在嘗試在IDictionary對象中存儲用戶guid的列表。每次用戶點擊該服務時,都會更新用戶的日期時間,以便跟蹤哪些用戶擁有活動的「會話」。問題是,每次我點擊該服務時,該列表都是空的。它似乎正在刪除每個肥皂請求上的值?自己託管的wcf服務是否有狀態?

您是否可以將信息存儲在跨多個服務請求可用的自託管服務中?

在此先感謝!

+1

像用戶列表一樣的持久性信息屬於持久性存儲(例如數據庫) –

+0

它是如何被自託管的(控制檯應用程序,Windows服務等)? –

回答

1

您需要更改InstanceContextMode。您可以通過添加以下編譯器指令的WCF類這樣做:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

這將運行WCF服務爲各種各樣的單身。查看更多關於WCF Instance Context Mode

然後,你應該用你的單件對象構建您的服務主機。下面是從一個工作示例,其中我在做類似的事情代碼:

  private ServiceHost serviceHost; 

      if (serviceHost != null) 
       serviceHost.Close(); 

      if (log.IsInfoEnabled) 
       log.Info("Starting WCF service host for endpoint: " + ConfiguredWCFEndpoint); 

      // Create our service instance, and add create a new service host from it 
      ServiceLayer.TagWCFService service = new ServiceLayer.TagWCFService(ApplicationName, 
       ApplicationDescription, 
       SiteId, 
       ConfiguredUpdateRateMilliseconds); 

      serviceHost = new ServiceHost(service, new Uri(ConfiguredWCFEndpoint)); 

      // Open the ServiceHostBase to create listeners and start listening for messages. 
      serviceHost.Open(); 

正如其他人禮貌指出,如果你不熟悉它是如何工作的,或者如果這個可以有「後果」這不是一個非常適合您的特定應用。

+2

這有**許多**和**發育**的後果 - 要麼你已經成功地將所有請求序列化(例如,你的表現會吸**大時間),或者你必須確保您的WCF服務類中的代碼是完全可重入**和線程安全的 - **不是**一個簡單的任務即使對於高級程序員也是如此!避免單身 - 如果可能的話! –

+0

我嘗試添加該屬性,並且它仍然沒有在請求之間維護字典中的數據。還有什麼我必須補充? – spyter

+0

創建ServiceHost對象時,將它傳遞給您的單例對象(您創建的WCF類對象)。我編輯了答案來表明這一點。 – landoncz

2

它是在每個實例的基礎上。 I.e默認情況下會話。

看一看this

當一個服務合同設置 System.ServiceModel.ServiceContractAttribute.SessionMode屬性 System.ServiceModel.SessionMode.Required,該合同是說, 所有呼叫(即是,支持 調用的基礎消息交換)必須是同一個對話的一部分。

2

如果您需要在請求之間存儲事物,您需要創建具有適當鎖定的靜態字典,以在這些請求進入時存儲這些請求,或將此信息存儲在數據庫(或其他外部存儲)中並檢查看看它在每個方法調用中是否存在。這是因爲服務類是在每個客戶端請求上實例化的。

既然你當用戶點擊這將是更好的服務進行查找,看是否這是一個活躍的用戶或不通過比較日期時間字段已經更新的用戶日期時間。這具有在每次調用時都準確的優點(如果服務重新啓動,字典可能會與數據庫不同步)。數據庫已經具有處理併發性的機制,所以不要將自己的鎖定解決方案圍繞單例對象進行滾動,而是將複雜性推向數據存儲。

如果第二個解決方案速度不夠快(並且您已經對應用程序進行了配置並確定它是瓶頸),那麼另一個選擇是在db前使用某種緩存解決方案,以便可以首先檢查數據在去內存之前在內存中。這個緩存對象需要像字典一樣是靜態的,並且與其他任何多線程應用程序一樣,具有與鎖定相同的缺陷。

編輯:如果此託管的WCF服務正在用作Silverlight應用程序用戶的會話存儲並且數據未存儲在外部數據存儲中,那麼您最好確保跟蹤它們是否處於活動狀態任務關鍵。如上所述,這些數據不能保證是正確的。

根據接受的答案,如果您的服務出現故障並需要重新啓動(因爲這是自託管的,建議您監視故障事件),您必須處理服務主機並實例化一個新服務主機。 Guid數據可以保留的唯一方法是在重新啓動之間重新啓動服務(假設主機應用程序本身未重新啓動,這是一個不同的問題)。

private Dictionary<Guid,string> _session; 

Service service = new Service(_session); 
_serviceHost = new ServiceHost(service, GetUriMethodInHostApp()); 

更好的做法是將它存儲在外部並按照@marc_s的建議進行查找。然後,這種複雜性消失。

+0

我試圖讓我的字典是靜態的,它仍然丟失每個請求上的數據。儘管我在服務上指定了[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]。 – spyter

1

如果你沒有什麼涉及鎖定和線程安全的特定代碼,您可以使用的NoSQL數據庫來存儲會話數據,像MongoDBRavenDB

像@marc_s,我覺得用單例模式是一件有風險的事情,你必須非常小心地創建自己的線程安全會話機制。