2016-09-16 10 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

Btw、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返信いただきありがとうございます。私は単一のサーバーを使用しているだけでなく、 "セッション収集"データはすべてのクライアントで共有されています。この種のデータの不一致に対するこれ以上の示唆はありますか? –

+0

@NileshWaghが私の答えを更新しました。それをチェックできますか? – alltej

+0

こんにちは@alltej、私はあなたの編集した答えに応じて変更を追加しました。ビットはまだ私は同じ問題に直面しています。 –

1

あなたはSessionの代わりCacheにクライアント固有の情報を格納する必要があります。Cacheは(共有)アプリケーション全体のWeb APIは(状態をキャッシュしませんのAPI)を念頭に置いたRESTfulで構築されており、RESTfulサービスはステートレスでなければなりませんよう

しかし、それはお勧めしませんのためにする必要があります。ステートレスアプリケーションでは、多くの利点を持っている:

  • は、メモリ使用量
  • 優れたスケーラビリティを削減:あなたのアプリケーションは、より良いスケール。何百万人ものクライアントの情報を同時に保存するとどうなるでしょうか?
  • 負荷分散のシナリオが改善されました。すべてのサーバーが状態を失うことなくすべてのクライアントを処理できます。
  • セッションの有効期限の問題。

クライアントの状態を保存したい場合は、とにかくできます。 ASP.NET Web API session or something?

一般に、Webサーバー上のローカルにキャッシュ状態が悪い(SessionとローカルMemoryCacheの両方)。キャッシュは多くの理由で失われる可能性があります。

  • アプリケーションプールリサイクル。あなたの要件についてはIIS

  • 負荷分散環境
  • 複数のワーカープロセス:

    各クライアント秒ごとに 同期目的のために、サーバからセッション情報とアクセスリストを取得します。アクセスが変更されると、 クライアントの機能が変更されます(有効/無効)。

    クライアントが同期呼び出しを送信したときにすぐに他のクライアントを新しいアクセスリストに更新するかどうかはわかりません。その場合は、SignalRが良い選択です。

    それ以外の場合は、更新されたアクセスリストを別の場所(共有キャッシュまたはデータベース内)に格納して、別の要求と再接続するたびに他のクライアントを更新するだけで済みます。

  • 0

    @ScottHanselmanは、.NET 4hereのバグについて語った。修正プログラムがhttp://support.microsoft.com/kb/2828843であるとすることができます

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

    を流し

    が無効になって実行コンテキストの下でメモリキャッシュのインスタンスを作成します。

    一時的な修正:私は、この修正プログラムの助けあなたを願っていますここにリクエストしてください:https://support.microsoft.com/contactus/emailcontact.aspx?scid=sw;%5BLN%5D;1422

    関連する問題