我为.Net MemoryCache编写了自己的自定义更改监视器类。它似乎初始化很好,但是当我尝试将它添加到Cache时,它会抛出一个InvalidOperation异常“该方法已经被调用,并且只能被调用一次。”
我的更改监控类
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);
Set调用抛出了无效的操作异常,这很奇怪,因为根据MSDN文档,它只抛出ArgumentNull,Argument,ArgumentOutOfRange和NotSupported Exceptions。
我确信我一定是犯了一个简单的错误。但很难找到关于编写自己的自定义更改监视器的好文档或示例。任何帮助将不胜感激
答案 0 :(得分:6)
我知道评论有答案,但我希望它更明显......
当使用ChangeMonitor
时,如果缓存条目不存在,它将立即触发
MSDN documentation states it this way:
任何受监控的条目都被视为已更改 原因如下:
A)键在通话时不存在 CreateCacheEntryChangeMonitor方法。在那种情况下,由此产生 CacheEntryChangeMonitor实例立即设置为已更改 州。这意味着当代码随后绑定一个 更改通知回调,立即触发回调。
B)已从缓存中删除关联的缓存条目。这个可以 如果明确删除了条目,它是否过期,或者是否过期,则会发生 被驱逐以恢复记忆
答案 1 :(得分:2)
我刚刚遇到同样的问题,并且进行了自己的调查,发布了一个迟到的答案。
当您使用缓存项目策略注册变更监视器时policy.ChangeMonitors.Add(cm)
- CacheItemPolicy
实施通过ChangeMonitor.NotifyOnChanged
在其上注册自己的变更回调。您不应该调用cm.NotifyOnChanged
来注册另一个回调,否则它会在此时抛出The method has already been invoked, and can only be invoked once
。
相反,请使用CacheItemPolicy.UpdateCallback
或CacheItemPolicy.RemovedCallback
来更新/删除缓存项,例如如this blog post中所述。
答案 2 :(得分: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)
我已经搜索了好几个小时......直到逻辑之光袭击了我:
我正在使用一个被重用的静态策略对象..(我中的一些无意识进程如果它们相等则重用所有对象,也许我害怕构造在内存中消耗一些字节的对象)
通过为缓存中的每个项创建新的策略对象,错误消失了。如果你考虑它,那就很合乎逻辑了。