在域未处理的异常之后,MemoryCache始终返回null

时间:2013-09-10 16:22:46

标签: c# asp.net azure

我遇到MemoryCache(System.Runtime.Caching)的问题。关于此对象的其他问题,我发现在域未处理的异常之后没有缓存任何值。

例外是:

Exception: System.TypeInitializationException 
Message: The type initializer for 'System.Web.Util.ExecutionContextUtil' threw an exception. 
Trace: 
at System.Web.Util.ExecutionContextUtil.RunInNullExecutionContext(Action callback) 
at System.Web.Hosting.ObjectCacheHost.System.Runtime.Caching.Hosting.IMemoryCacheManager.UpdateCacheSize(Int64 size, MemoryCache memoryCache) 
at System.Runtime.Caching.CacheMemoryMonitor.GetCurrentPressure() 
at System.Runtime.Caching.MemoryMonitor.Update() 
at System.Runtime.Caching.MemoryCacheStatistics.CacheManagerThread(Int32 minPercent) 
at System.Threading.ExecutionContext.runTryCode(Object userData) 
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) 
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
at System.Threading._TimerCallback.PerformTimerCallback(Object state)

Caused by Exception: System.Exception Message: Type 'System.Threading.ExecutionContext' does not have a public property named 'PreAllocatedDefault'. 
Trace: at System.Web.Util.ExecutionContextUtil.GetDummyDefaultEC() 
at System.Web.Util.ExecutionContextUtil..cctor() 

异常似乎是在2到5分钟后抛出。我认为解决这个异常应该解决我的问题,因为缓存不会被处理掉。

问题始于昨天19h,即使我使用它3个月...... 自12天以来,生产没有任何变化。服务器托管在Azure上(os是Windows Server 2008 R2)

修改 异常处理程序

public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e) {
        System.Threading.Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Global_UnhandledException);
        System.Threading.Thread.GetDomain().DomainUnload += new EventHandler(Global_DomainUnload);
    }
}

MemoryCache Wrapper

    public abstract class MemoryCacheManager : ICacheManager
{

    private MemoryCache MemoryCache;

    protected MemoryCacheManager()
    {
        MemoryCache = new MemoryCache("Common.Utils.MemoryCacheManager");
    }

    private void ItemRemoved(CacheEntryRemovedArguments arguments)
    {
        switch (arguments.RemovedReason)
        {
            case CacheEntryRemovedReason.CacheSpecificEviction:
                LogManager.Instance.Log(arguments.CacheItem.Key + " : CacheSpecificEviction");
                break;
            case CacheEntryRemovedReason.ChangeMonitorChanged:
                LogManager.Instance.Log(arguments.CacheItem.Key + " : ChangeMonitorChanged");
                break;
            case CacheEntryRemovedReason.Evicted:
                LogManager.Instance.Log(arguments.CacheItem.Key + " : Evicted");
                break;
            case CacheEntryRemovedReason.Expired:
                LogManager.Instance.Log(arguments.CacheItem.Key + " : Expired");
                break;
            case CacheEntryRemovedReason.Removed:
                LogManager.Instance.Log(arguments.CacheItem.Key + " : Removed");
                break;
        }

    }

    #region ICacheManager        
    public void Add(string key, object value, DateTimeOffset absoluteExpiration)
    {
        var policy = new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration, RemovedCallback = ItemRemoved };
        Add(key, value, policy);
    }

    public void Add(string key, object value, TimeSpan slidingExpiration)
    {
        var policy = new CacheItemPolicy { SlidingExpiration = slidingExpiration, RemovedCallback = ItemRemoved };
        Add(key, value, policy);
    }

    private void Add(string key, object value, CacheItemPolicy policy)
    {
        MemoryCache.Add(key, value, policy);
        LogManager.Instance.Info(DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss") + " " + key + " : Added");
    }

    public object Get(string key)
    {
        return MemoryCache.Get(key);
    }

    public bool Exist(string key)
    {
        return MemoryCache.Contains(key);
    }

    public bool Remove(string key)
    {
        return MemoryCache.Remove(key) != null;
    }
    #endregion
}

缓存管理器

    public class CacheManager : MemoryCacheManager
{

    #region Singleton
    private static readonly CacheManager instance = new CacheManager();

    // Explicit static constructor to tell C# compiler ot to mark type as beforefieldinit
    static CacheManager() { }

    private CacheManager() 
        : base()
    {
    }

    public static CacheManager Instance
    {
        get
        {
            return instance;
        }
    }
    #endregion
}

首次调用Global_UnhandledException后,所有CacheManager.Instance.Get都返回null。

我的问题是:如何避免这种异常?或者如何使memorycache正常工作

3 个答案:

答案 0 :(得分:3)

我也遇到了异常,我可以使用HTTP模块输出到文本文件来捕获未处理的异常,这种异常往往发生在页面请求/响应执行之外。

message=The type initializer for 'System.Web.Util.ExecutionContextUtil' threw an exception.
stack= at System.Web.Util.ExecutionContextUtil.RunInNullExecutionContext(Action callback)
at System.Web.Hosting.ObjectCacheHost.System.Runtime.Caching.Hosting.IMemoryCacheManager.UpdateCacheSize(Int64 size, MemoryCache memoryCache)
at System.Runtime.Caching.CacheMemoryMonitor.GetCurrentPressure()
at System.Runtime.Caching.MemoryMonitor.Update()
at System.Runtime.Caching.MemoryCacheStatistics.CacheManagerThread(Int32 minPercent)
at System.Runtime.Caching.MemoryCacheStatistics.CacheManagerTimerCallback(Object state)
at System.Threading._TimerCallback.TimerCallback_Context(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading._TimerCallback.PerformTimerCallback(Object state)

type=System.Exception

message=Type 'System.Threading.ExecutionContext' does not have a public property named 'PreAllocatedDefault'.

stack=at System.Web.Util.ExecutionContextUtil.GetDummyDefaultEC()
at System.Web.Util.ExecutionContextUtil..cctor()

编辑:值得注意的是,抛出此异常后,缓存将完全停止工作。

我在研究问题时遇到过这个问题:

http://blogs.msdn.com/b/kwill/archive/2013/09/11/august-2013-windows-azure-guest-os-issue-with-system-runtime-caching-memorycache.aspx

在文中他们说:“此OS版本包含标准安全补丁,包括https://support.microsoft.com/kb/2862772(MS13-059)中的修复程序,这是Internet Explorer的累积安全更新。此IE补丁引入了回归在ASP.NET应用程序中使用System.Runtime.Caching.MemoryCache时会导致上述异常。“

后来,他们给出了三个解决方案,第一个是在应用修补程序之前回滚。第二个告诉你简单地避免使用MemoryCache(很好)。唯一的另一个解决方案就是等到修补这个问题并在10月初(2013年)提示。

“下一个Windows Azure客户操作系统版本将包含用于解决此问题的IE修补程序,并应在10月初开始向Azure推出。”

此页面的显示方式听起来好像这个问题只是Windows Azure的一个问题。但我认为它会影响任何具有此修补程序并运行ASP.NET应用程序的平台。虽然Windows 7(这是我的操作系统)的“关键”更新似乎是推出到Windows Server 2008的修补程序被标记为“中等”。这可能会有所帮助,因为虽然它会影响我的开发平台,但它不会影响我的生产服务器。我在下面的安全公告中找到了这些信息:

http://technet.microsoft.com/en-us/security/bulletin/ms13-059

有趣的是,当我不得不在ASP.NET应用程序中添加使用OutputCache进行子操作的解决方案时,我停止了这个问题,尽管我仍然继承MemoryCache。

我会包含我用过的代码,如果它派上用场,我会相信以下博客,为我节省了大量时间:

http://www.haneycodes.net/custom-output-caching-with-mvc3-and-net-4-0-done-right/

以下代码......

public class CustomMemoryCache : MemoryCache
    {
    public CustomMemoryCache(string name)
        : base(name)
        {
        }

    public override bool Add(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
        {
        System.Web.Caching.OutputCache.Providers[System.Web.Caching.OutputCache.DefaultProviderName].Add(key, value, absoluteExpiration.DateTime);
        return true;
        }

    public override object Get(string key, string regionName = null)
        {
        return System.Web.Caching.OutputCache.Providers[System.Web.Caching.OutputCache.DefaultProviderName].Get(key);
        }
    }

在我的Global.asax.cs中:

protected void Application_Start()
    {
        OutputCacheAttribute.ChildActionCache = new CustomMemoryCache("MyCache");
    }

提供者:

public class MyCacheItem
    {
    public Object ItemData { get; set; }
    public DateTime UtcExpiry { get; set; }
    public DateTime UtcAdded { get; set; }
    }

public class MyOutputCacheProvider: OutputCacheProvider
    {
    private readonly Dictionary<String, MyCacheItem> CacheDictionary = new Dictionary<String, MyCacheItem>(); 

    public override object Get(string key)
        {
        lock(CacheDictionary)
            {
            if (!CacheDictionary.ContainsKey(key))
                return null;

            var Item = CacheDictionary[key];

            // Item has expired?
            if (Item.UtcExpiry < DateTime.UtcNow)
                {
                Remove(key);
                return null;
                }

            return Item.ItemData;
            }
        }

    public override object Add(string key, object entry, DateTime utcExpiry)
        {
        lock (CacheDictionary)
            {
            if (!CacheDictionary.ContainsKey(key))
                {
                MyCacheItem CacheItem = new MyCacheItem
                    {
                        ItemData = entry, 
                        UtcExpiry = utcExpiry,
                        UtcAdded =  DateTime.UtcNow
                    };

                CacheDictionary.Add(key, CacheItem);
                return CacheItem.ItemData;
                }

            var Item = CacheDictionary[key];
            return Item.ItemData;
            }
        }

    public override void Set(string key, object entry, DateTime utcExpiry)
        {
        lock (CacheDictionary)
            {
            if (!CacheDictionary.ContainsKey(key))
                {
                Add(key, entry, utcExpiry);
                return;
                }

            CacheDictionary[key].ItemData = entry;
            CacheDictionary[key].UtcExpiry = utcExpiry;
            }
        }

    public override void Remove(string key)
        {
        lock (CacheDictionary)
            {
            if (!CacheDictionary.ContainsKey(key))
                return;

            CacheDictionary.Remove(key);
            }
        }
    }

最后,web.config:

<system.web>        
    <caching>
        <outputCache defaultProvider="MyCache">
            <providers>
                <add name="MyCache" type="MyApp.Namespace.MyOutputCacheProvider"/>
            </providers>
        </outputCache>
    </caching>
</system.web>

答案 1 :(得分:1)

答案 2 :(得分:0)

所有内存中对象都将消失(内存中会话状态,缓存,静态值......),因为未处理的异常会破坏进程。对于ASP.Net,它意味着IIS(或dev服务器)将重新启动应用程序,并且您不会缓存数据。