Simplest explanation I can produce:
In my .NET1.1 web app I create a file on disc, in the Render method, and add an item to the Cache to expire within, say, a minute. I also have a callback method, to be called when the cache item expires, which deletes the file created by Render. In the Page_Init method I try to access the file which the Render method wrote to disc. Both these methods have a lock statement, locking a private static Object.
Intention:
To create a page which essentially writes a copy of itself to disc, which gets deleted before it gets too old (or out of date, content-wise), while serving the file if it exists on disc.
Problem observed:
This is really two issues, I think. Requesting the page does what I expect, it renders the page to disc and serves it immediately, while adding the expiry item to the cache. For testing the expiry time is 1 minute.
I then expect that the callback method will get called after 60 seconds and delete the file. It doesn't.
After another minute (for the sake of argument) I refresh the page in the browser. Then I can see the callback method get called and place a lock on the lock object. The Page_Init also gets called and places a lock on the same object. However, both methods appear to enter their lock code block and proceed with execution.
This results in: Render checks file is there, callback method deletes file, render method tries to serve now-deleted-file.
Horribly simplified code extract:
public class MyPage : Page
{
private static Object lockObject = new Obect();
protected void Page_Init(...)
{
if (File.Exists(...))
{
lock (lockObject)
{
if (File.Exists(...))
{
Server.Transfer(...);
}
}
}
}
protected override void Render(...)
{
If (!File.Exists(...))
{
// write file out and serve initial copy from memory
Cache.Add(..., new CacheItemRemovedCallback(DoCacheItemRemovedCallback));
}
}
private static void DoCacheItemRemovedCallback(...)
{
lock (lockObject)
{
If (File.Exists(...))
File.Delete(...);
}
}
}
Can anyone explain this, please? I understand that the callback method is, essentially, lazy and therefore only calls back once I make a request, but surely the threading in .NET1.1 is good enough not to let two lock() blocks enter simultaneously?
Thanks,
Matt.