Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET HttpModule RewritePath virtual directory cache not refreshing

I have an ASP.NET IHttpModule implementation designed to rewrite paths for serving files. The module handles only one event, PostAuthenticateRequest, as follows:

void context_PostAuthenticateRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.Path.ToLower().Contains("foobar"))
    {
        HttpContext.Current.RewritePath("virtdir/image.png");
    }
}

The path "virtdir", is a virtual directory child of the application. The application itself runs in a typical location: C:\inetpub\wwwroot\IisModuleCacheTest\ The virtual directory "virtdir" is mapped to C:\TestVirtDir\

A request to http://myserver/iismodulecachetest/foobar will, as expected, return image.png from the virtual directory. Equally, a request to http://myserver/iismodulecachetest/virtdir/image.png will return the same image file.

I then perform the following:

  1. Request http://myserver/iismodulecachetest/foobar
  2. Directly modify C:\testvirtdir\image.png (change its colour in paint and re-save).
  3. Repeat.

After anywhere between 1 and 20 repeats spaced a few seconds apart, the image returned will be an out of date copy.

Once upset, the server will only return the current version after an unknown amount of time elapses (from 10 seconds up to a few minutes). If I substitute the URL in step 1 with http://myserver/iismodulecachetest/virtdir/image.png, the problem doesn't appear to arise. But strangely enough, after the problem has arisen by using the "foobar" URL, the direct URL also starts returning an out of date copy of the image.

Pertinent Details:

  1. A recycle of the app-pool resolves the issue.
  2. Waiting a while resolves the issue.
  3. Repeatedly re-saving the file doesn't appear to have an effect. I'd wondered if a "file modified" event was getting lost, but once stuck I can save half a dozen modifications and Iis stil doesn't return a new copy.
  4. Disabling cache in web.config made no difference. <caching enabled="false" enableKernelCache="false" />
  5. The fact that this is a virtual directory seems to matter, I could not replicate the issue with image.png being part of the content of the application itself.
  6. This is not a client-cache, it is definitely the server returning an out of date version. I have verified this by examining request headers, Ctrl+F5 refreshing, even using separate browsers.
  7. I've replicated the issue on two machines. Win7 Pro 6.1.7601 SP1 + IIS 7.5.7600.16385 and Server 2008 R2 6.1.7601 SP1 + IIS 7.5.7600.16385.

Edit - More Details:

  1. Disabling cache and kernel cache at the server level makes no difference.
  2. Adding an extension to the URL makes no difference http://myserver/iismodulecachetest/foobar.png.
  3. Attaching a debugger to IIS shows the context_PostAuthenticateRequest event handler is being triggered each time and behaving the same way whether or not the cache is stuck.

Edit2 - IIS Logs:

I enabled "Failed Request Tracing" in IIS (interesting how this works for non-failed requests also if configured appropriately. The pipeline is identical up until step 17 where the request returning the out of date version clearly shows a cache hit.

The first request looks just fine, with a cache miss:

Good Request

But once it gets stuck, it repeatedly shows a cache hit:

Bad Request

The events after the cache hit are, understandably, quite different than the cache miss scenario. It really just looks like IIS is perfectly content to think its file cache is up to date, when it is definitely not! :(

A little further down the stack we see first request:

Good Request 2

And then subsequent (faulty) cache-hit request:

Bad Request 2

Also note that the directory is apparently monitored, as per FileDirmoned="true".

like image 928
Snixtor Avatar asked Nov 12 '22 12:11

Snixtor


1 Answers

You can do something like below.

void context_PostAuthenticateRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.Path.ToLower().Contains("foobar"))
    {
        Random rnd = new Random();
        int randomNumber = rnd.Next(int.MinValue, int.MaxValue);
        HttpContext.Current.RewritePath("virtdir/image.png?"+randomNumber);
    }
}
like image 149
Cagatay Avatar answered Nov 15 '22 13:11

Cagatay