2016-09-16 95 views
5

我已經使用WebAPI2實現了REST服務,該服務實現了管理由正在訪問服務的不同客戶端創建和加入的不同會話。如何管理ASP.NET WebApi2中的緩存?

會話包含有關應用程序功能訪問的信息和已加入同一會話的參與者的信息。

每個客戶端都會從服務器獲取會話信息和訪問列表,以便每秒鐘進行同步。根據訪問更改,客戶端功能將改變(啓用/禁用)。

我正在使用MemoryCache類將會話信息存儲在WebAPI服務中,如下所示。

public static class SessionManager{ 
private static object objForLock = new object(); 
public static List<Session> SessionCollection 
{ 
    get 
    { 
     lock (objForLock) 
     { 
      MemoryCache memoryCache = MemoryCache.Default; 
      return memoryCache.Get("SessionCollection") as List<Session>; 
      // return HttpContext.Current.Application["SessionCollection"] as List<Session>; 
     } 
    } 
    set 
    { 
     lock (objForLock) 
     { 
      MemoryCache memoryCache = MemoryCache.Default; 
      memoryCache.Add("SessionCollection", value, DateTimeOffset.UtcNow.AddHours(5)); 
      //HttpContext.Current.Application["SessionCollection"] = value; 
     } 
    } 
} 

}

我的問題是關於高速緩存的不一致的行爲。

當客戶端發送同步呼叫時,它會產生不一致的結果。對於某些請求,客戶端獲取正確的數據,並且對於某些請求,客戶端在某些請求後獲得空數據替代。

我已添加調試器並監視對象爲空結果,然後「memoryCache.Get(」SessionCollection「)」也爲null。經過一些連續的請求後,它會再次適當。我不明白爲什麼這個對象不是持久的。

另外,我試過「HttpContext.Current.Application [」SessionCollection「]」「,但同樣的問題在那裏。

我已閱讀約「應用程序池回收」,它在微粒時間後回收所有緩存。如果我的緩存對象被應用程序池回收循環使用,那麼如何再次獲取此對象?

請有人可以幫助我擺脫這個問題。提前致謝。

+0

只是想仔細檢查您的服務器時間是否也設置爲UTC。超時值是否有可能在你期望之前達到? – ManOVision

+0

順便說一句,MemoryCache是​​線程安全的,因此不需要鎖定 –

+0

其中。你使用的是.NET版本嗎? – RAM

回答

0

只需謹慎,MemoryCache將數據保存在單個服務器的內存中。因此,如果您有多個Web服務器(位於負載均衡器之前),則該緩存將無法供其他服務器使用。您還可以使用緩存名稱 - 「SessionCollection」。這些數據將被分享給所有客戶。如果您需要將數據存儲在每個客戶端獨有的緩存中,則需要將令牌(guid)返回給客戶端,並使用該令牌在隨後的請求中獲取/更新緩存中的數據。

嘗試引入一個類級別的變量。所以你的代碼如下所示。 (某些代碼刪除爲清楚起見)

private readonly MemoryCache _memCache = MemoryCache.Default; 

....

return _memCache.Get("SessionCollection") as List<Session>; 

...

_memCache .Add("SessionCollection", value, DateTimeOffset.UtcNow.AddHours(5)); 
+0

@alltej感謝您的回覆。我正在使用單個服務器以及「Session Collection」數據爲所有客戶端共享。對於這種數據不一致的更多建議? –

+0

@NileshWagh更新了我的答案。你能檢查一下嗎? – alltej

+0

嗨@alltej,我已根據您編輯的答案添加更改,位仍然我面臨同樣的問題。 –

1

,可以儲存在Session,而不是Cache客戶的具體信息。Cache應該是爲整個應用程序(共享)

但是,不建議爲Web API與REST風格的建在思想和RESTful服務應該是無狀態(的API不緩存狀態)。無狀態的應用有很多好處:

  • 減少內存使用
  • 更好的擴展性:您的應用程序更好地伸縮。如果您同時存儲數百萬客戶端的信息,會發生什麼情況。
  • 更好的負載平衡方案:每個服務器都可以處理每個客戶端而不會丟失狀態。
  • 會話到期問題。

如果你想存儲客戶端狀態,你可以做任何事情。請嘗試建議在以下崗位:本地ASP.NET Web API session or something?

一般來說,緩存狀態在Web服務器上是不好的(包括Session和當地MemoryCache)。緩存可能會因多種原因丟失:

  • 應用程序池回收。
  • 負載均衡環境
  • 在IIS
  • 多個工作進程

關於你的要求:

每個客戶端從服務器獲取會話信息和訪問名單上的每一秒 同步的目的。根據訪問更改, 客戶端功能將改變(啓用/禁用)。

我不確定您是否想在客戶端發送同步呼叫時立即用新的訪問列表更新其他客戶端。如果是這樣的話,SignalR將是更好的選擇。

否則,您可以將更新後的訪問列表存儲在某處(共享緩存或甚至數據庫中),並在其他客戶端與其他請求重新連接時更新其他客戶端。

0

@ScottHanselman表示關於.NET 4here中的一個錯誤。我希望此修復程序幫助您:

臨時修復

下創建禁用執行上下文的內存緩存實例流

using (ExecutionContext.SuppressFlow())  { 
      // Create memory cache instance under disabled execution context flow 
     return new YourCacheThing.GeneralMemoryCache(…); 
} 

修補程序http://support.microsoft.com/kb/2828843,你可以在此處要求:https://support.microsoft.com/contactus/emailcontact.aspx?scid=sw;%5BLN%5D;1422