2011-04-01 45 views
8

我寫我自己的自定義更改監視器類爲.NET的MemoryCache。它似乎初始化很好,但是當我試圖將它添加到Cache時,它會拋出一個InvalidOperation異常「該方法已經被調用,並且只能被調用一次。」定製ChangeMonitor對於.NET的MemoryCache導致無效操作異常

我更改監視器類

internal class MyChangeMonitor : ChangeMonitor 
{ 
    private Timer _timer; 
    private readonly string _uniqueId; 
    private readonly TypeAsOf _typeAsOf; 
    private readonly string _tableName; 

    public GprsChangeMonitor(TypeAsOf typeAsOf, string tableName) 
    { 
     bool initComplete = false; 
     try 
     { 
      _typeAsOf = typeAsOf; 
      _tableName = tableName; 

      _uniqueId = Guid.NewGuid().ToString(); 
      TimeSpan ts = new TimeSpan(0, 0, 5, 0, 0); 
      _timer = new Timer {Interval = ts.TotalMilliseconds}; 
      _timer.Elapsed += CheckForChanges; 
      _timer.Enabled = true; 
      _timer.Start(); 
      initComplete = true; 
     } 
     finally 
     { 
      base.InitializationComplete(); 
      if(!initComplete) 
       Dispose(true); 
     } 
    } 

    void CheckForChanges(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     //check for changes, if different 
     base.OnChanged(_typeAsOf); 
    } 
} 

我用它來創建高速緩存策略和鍵/值對添加到緩存

 CacheItemPolicy policy = new CacheItemPolicy 
     { 
      UpdateCallback = OnCacheEntryUpdateCallback 
     }; 


     policy.AbsoluteExpiration = SystemTime.Today.AddHours(24); 
     //monitor the for changes 
     string tableName = QuickRefreshItems[type]; 
     MyChangeMonitor cm = new MyChangeMonitor(typeAsOf, tableName); 
     policy.ChangeMonitors.Add(cm); 
     cm.NotifyOnChanged(OnRefreshQuickLoadCacheItems); 



     MyCache.Set(cacheKey, value, policy); 

的集調用的代碼引發無效操作異常,其很奇怪,因爲根據MSDN文檔,它只會拋出ArgumentNull,Argument,ArgumentOutOfRange和NotSupported Exceptions。

我相信,我必須做一個簡單的錯誤。但是在編寫自己的自定義更改監視器時很難找到很好的文檔或示例。任何幫助,將不勝感激

+0

可以附加一個調試器,關閉僅我的代碼,然後在例外打破看到調用堆棧是什麼的出現InvalidOperationException? – 2011-04-01 23:13:25

+0

堆棧跟蹤不是很有幫助。它在System.Runtime.Caching.ChangeMonitor.NotifyOnChanged(OnChangedCallback onChangedCallback)中,但它不在NotifyOnChanged的回調中,因爲它沒有被調用。 – Keith 2011-04-04 12:16:47

+7

顯然,我必須在將項目添加到緩存後將更改監視器添加到策略中。如果我之前添加它,那麼我會得到異常。 – Keith 2011-04-04 12:34:29

回答

6

我知道的意見有答案,但我想這是更明顯...

當使用ChangeMonitor,它會立即解僱如果緩存條目不存在。
MSDN documentation states it this way

A monitored entry is considered to have changed for any of the following reasons:

A) The key does not exist at the time of the call to the CreateCacheEntryChangeMonitor method. In that case, the resulting CacheEntryChangeMonitor instance is immediately set to a changed state. This means that when code subsequently binds a change-notification callback, the callback is triggered immediately.

B) The associated cache entry was removed from the cache. This can occur if the entry is explicitly removed, if it expires, or if it is evicted to recover memory

1

我有完全相同的錯誤:

Source: System.Runtime.Caching 
    Exception type: System.InvalidOperationException 
    Message: The method has already been invoked, and can only be invoked once. 
    Stacktrace: at System.Runtime.Caching.ChangeMonitor.NotifyOnChanged(OnChangedCallback onChangedCallback) 
        at System.Runtime.Caching.MemoryCacheEntry.CallNotifyOnChanged() 
        at System.Runtime.Caching.MemoryCacheStore.AddToCache(MemoryCacheEntry entry) 
        at System.Runtime.Caching.MemoryCacheStore.Set(MemoryCacheKey key, MemoryCacheEntry entry) 
        at System.Runtime.Caching.MemoryCache.Set(String key, Object value, CacheItemPolicy policy, String regionName) 

我搜索了好幾個小時,直到..邏輯的光讓我吃驚:

我正在使用一個被重用的靜態策略對象..(我的一些無意識過程在所有對象重用時,如果它們是平等的,也許我害怕構造在內存中消耗一些字節的對象)

通過爲緩存中的每個項目創建新的策略對象,錯誤消失了。如果你仔細想想,這很合乎邏輯。

1

發佈一個遲到的回答我剛剛遇到了同樣的問題,並進行自己的調查。

當您使用緩存項目策略註冊您的更改監視器時 - policy.ChangeMonitors.Add(cm) - CacheItemPolicy實施通過ChangeMonitor.NotifyOnChanged在其上註冊其自己的更改回調。您不應該調用cm.NotifyOnChanged來註冊另一個回調,否則它會在此時拋出The method has already been invoked, and can only be invoked once

相反,使用CacheItemPolicy.UpdateCallbackCacheItemPolicy.RemovedCallback更新/刪除緩存項,例如如this blog post中所述。

相關問題