自定义ChangeMonitor for .Net MemoryCache导致无效的操作异常

时间:2011-04-01 19:37:02

标签: c# .net invalidoperationexception

我为.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。

我确信我一定是犯了一个简单的错误。但很难找到关于编写自己的自定义更改监视器的好文档或示例。任何帮助将不胜感激

3 个答案:

答案 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.UpdateCallbackCacheItemPolicy.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)

我已经搜索了好几个小时......直到逻辑之光袭击了我:

我正在使用一个被重用的静态策略对象..(我中的一些无意识进程如果它们相等则重用所有对象,也许我害怕构造在内存中消耗一些字节的对象)

通过为缓存中的每个项创建新的策略对象,错误消失了。如果你考虑它,那就很合乎逻辑了。