2015-10-05 37 views
0

我有一個項目,我們使用服務體系結構,與Ninject解決我們的服務。幾乎所有的服務都使用異步。如何使用IoC緩存異步服務?

現在,我想添加緩存到幾個服務。

我從來沒有在異步方法中使用緩存,所以我不確定如何去做。我只知道作爲HttpContext.Current爲null,我目前得到這個錯誤:

enter image description here

所以,我應該去什麼樣的戰略,使這項工作?

我的IoC設置:NinjectWebCommon.cs:

private static void RegisterServices(IKernel kernel) 
     { 
      kernel.Bind<Context>().To<Context>().InRequestScope(); 
      kernel.Bind<UserManager<User>>().To<UserManager>().InTransientScope(); 
      kernel.Bind<IUserTokenProvider<User, string>>().ToMethod((x) => 
      { 
       var provider = OwinConfig.DataProtectionProvider; 
       return new DataProtectorTokenProvider<User>(provider.Create("ASP.NET Identity")); 
      }).InTransientScope(); 

      kernel.Bind<ICacheService>().To<HttpCache>();  
      kernel.Bind<IUserService>().To<UserService>(); 
      // Lots of nice services 

     } 

我ICacheService:

public interface ICacheService 
{ 
    object GetById(string cacheKey); 
    object Create(string cacheKey, object obj); 
    object Create(string cacheKey, object obj, DateTime expire); 
    void Delete(string cacheKey); 
    void DeleteByContaining(string containing); 
    string GetCacheKey(string methodName, string value); 
    bool ContainsKey(string cacheKey); 
} 

CacheService:

public class HttpCache : ICacheService 
    { 
     private static readonly ILog logger = LogManager.GetLogger(typeof (HttpCache)); 


     public object GetById(string cacheKey) 
     { 
      if (ContainsKey(cacheKey)) 
      { 
       return HttpContext.Current.Cache[cacheKey]; 
      } 

      return null; 
     } 

     public object Create(string cacheKey, object obj) 
     { 
      return Create(cacheKey, obj, DateTime.UtcNow.AddHours(5)); 
     } 

     public object Create(string cacheKey, object obj, DateTime expire) 
     { 
      if (!ContainsKey(cacheKey)) 
      { 
       HttpContext.Current.Cache.Insert(cacheKey, 
        obj, 
        null, 
        expire, 
        Cache.NoSlidingExpiration); 
      } 
      return GetById(cacheKey); 
     } 

     public void Delete(string cacheKey) 
     { 
      HttpContext.Current.Cache.Remove(cacheKey); 
     } 

     public void DeleteByContaining(string containing) 
     { 
      List<string> deleteList = new List<string>(); 
      HttpContext oc = HttpContext.Current; 

      // find all cache keys in the system... maybe insane? I don't know lol 
      IDictionaryEnumerator en = oc.Cache.GetEnumerator(); 
      while (en.MoveNext()) 
      { 
       var k = en.Key.ToString(); 
       if (k.Contains(containing)) 
       { 
        deleteList.Add(k); 
       } 
      } 

      foreach (var del in deleteList) 
      { 
       Delete(del); 
      } 
     } 


     public bool ContainsKey(string cacheKey) 
     { 
      return HttpContext.Current.Cache[cacheKey] != null; 
     } 

     public string GetCacheKey(string methodName, string value) 
     { 
      return string.Format("{0}_{1}", methodName, value); 
     } 
    } 

手機號碼:

public async Task<City> GetById(int id) 
     { 

      var cacheKey = _cacheService.GetCacheKey(MethodBase.GetCurrentMethod().Name, id.ToString()); 
      if (!_cacheService.ContainsKey(cacheKey)) 
      { 
       var city = await _db.Cities.FirstAsync(c => c.Id == id); 


       _cacheService.Create(cacheKey, city); 
       return city; 
      } 
      return (City)_cacheService.GetById(cacheKey); 
     } 
+0

@AlexeiLevenkov可能因爲我很愚蠢 - 有很高的可能性!感謝您的鏈接 –

+0

@AlexeiLevenkov所以,你說,如果我直接使用System.Web.HttpRuntime.Cache,我會安全嗎?請發表一個答案 - 也歡迎您取笑我的愚蠢:D –

+0

或者,使用'System.Runtime.Caching'。 – howcheng

回答

3

HttpContext.Current.Cache是訪問ASP.Net全局Cache對象(另一個用於請求生命期是Page.Cache)的幾個快捷方式之一。如果您需要訪問外部緩存請求,請使用HttpRuntime.Cache。 (在Accessing the ASP.NET Cache from a Separate Thread?還覆蓋)

注:

  • 注意,其實你沒有得到HttpContext.Current可能是更大的問題的症狀 - 你可以期望代碼與HttpContext組運行,但它不是,沿與文化......是否真的問題是你的問題是開放的問題,但至少檢查你的代碼是不是意外地使用.ConfigureAwait(false),Task.Run或手動安排線程池上的工作。
  • 雖然從緩存中添加/讀取單個項目是線程安全的,但當您希望多個條目保持一致時,請小心 - 您可能需要鎖定。
  • 請注意不要將用戶特定的數據放入緩存中,尤其是如果緩存處於IOC級別,並且沒有直接信息(無論結果是否是用戶特定的)。