System.Runtime.Caching "forgets" about caching when the debugger is attached
I have a suite of application components that require the persistence of a large business object collection in order to achieve reasonable performance. This is essentially data that is read from the database 开发者_如何转开发and hydrated into objects for later reuse.
This object collection was originally implemented in .net 3.5, so In order to achieve this persistence when loaded by an ASP.Net runtime the HttpRuntime.Cache was used, and if it was loaded by a win forms client the enterprise library caching block was used.
Now, with .net 4.0 the System.Runtime.Caching is available for these requests. The following pattern was implemented for cached item get.
Public Function GetCachedObject(cacheKey as String) as Object
Dim _returnValue as Object
SyncLock m_lockObject //some private lock object
Dim _cache as ObjectCache = MemoryCache.Default
//This is never found when debugging
If _cache.Item(cacheKey) IsNot Nothing Then
_returnValue = _cache.Item
Else
Dim _policy As New System.Runtime.Caching.CacheItemPolicy()
_policy.AbsoluteExpiration = DateTime.Now.AddHours(12)
Dim _obj as Object = MethodToGetAndHydrateObject()
_cache.Add(New CacheItem(cacheKey, _obj), _policy)
_returnValue = _obj
End If
End SyncLock
Return _returnValue
End Function
This seems to work, but only as long as there is no debugger (vs2010) attached.
Once I attach a debugger, the cache existence check noted above always returns nothing.
These are pretty much rote examples of how to use the cache from MSDN. Is there something that I am missing, or is this truly unexpected behavior?
Update: I see this happening when the components are hosted in ASP.net. I can build the DLL's, copy them to the site, run a few executions of steps and its fine. As soon as I attach the debugger and execute the steps again, it displays this behavior.
Update 2: As often happens here, a little while after I posted the question, I got a bit more error detail from the debugger output window. This error detail led me to this MS Connect article. It turns out that when using remoting (I am) to call into an ASP.NET hosted app, the MemoryCache.Default seems to tie its janitorial timers (cache cleanup, etc) to a thread context. When the thread context is no longer available, the callbacks fail and the MemoryCache.Default appears to stop working for all other attempts.
Adding the ExecutionContext.SuppressFlow() (as seen in the reworked example below) seems to stop this attachment.
Using ExecutionContext.SuppressFlow()
_cache = MemoryCache.Default
End Using
I put this in yesterday and its been peachy since.
not sure but I see the way you use the cache is a bit different from the example in MSDN, you are calling the add method instead of the Set.
Here the example I have found:
Private Sub btnGet_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim cache As ObjectCache = MemoryCache.[Default]
Dim fileContents As String = TryCast(cache("filecontents"), String)
If fileContents Is Nothing Then
Dim policy As New CacheItemPolicy()
Dim filePaths As New List(Of String)()
filePaths.Add("c:\cache\example.txt")
policy.ChangeMonitors.Add(New HostFileChangeMonitor(filePaths))
' Fetch the file contents.
fileContents = File.ReadAllText("c:\cache\example.txt")
cache.[Set]("filecontents", fileContents, policy)
End If
Label1.Text = fileContents
End Sub
found here: MemoryCache Class
you also say that this problem happens when you host your components in an ASP.NET application, in ASP.NET I personally would use the HttpContext.Current.Cache
it could be that this MemoryCache you are using now already does this, not sure because I have never used it before so can't tell, but how would it work if you change Add with Set and use the HttpContext's ones? Just check HpptContext.Current because it will be null if not running in an ASP.NET application.
another point you could pay attention to is, when you attach the debugger, do you really execute the Cache.Add/Set method?
精彩评论