aos
aos

Reputation: 71

Exception: Unable to generate etag from dependencies

I have an IHttpHandler in ASP.NET which serves some images. The handler sets the ETAG the following way:

context.Response.AddFileDependency(filename);                
context.Response.Cache.SetLastModifiedFromFileDependencies();
context.Response.Cache.SetETagFromFileDependencies();
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetMaxAge(new TimeSpan(999,0,0,0));
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetValidUntilExpires(true);                
context.Response.Cache.VaryByParams["*"] = true;
byte[] buffer = File.ReadAllBytes(filename);
context.Response.ContentType = MimeMapping.GetMimeMapping(mi.Mi_filename);
context.Response.StatusCode = 200;
context.Response.BinaryWrite(buffer);

Sometimes a get an System.Web.HttpException Exception under IIS7 which says:

Unable to generate etag from dependencies. One of the dependencies couldn't generate a unique id.

But I'm not able to reproduce the problem (I know that I can't test this with ASP.NET internal test web server). Has anybody a clue why this happens and what I can do to prevent this?

Upvotes: 5

Views: 756

Answers (2)

Cine
Cine

Reputation: 4402

The exception is thrown when CacheDependency.GetUniqueID() == null, so it should be possible to loop over a check for that.

var i = 0;
while (++i < 10)
{
    using (var cd = new CacheDependency(fi.FullName))
       if (cd.GetUniqueID() != null) break;
    Thread.Sleep(5*i);
}
if (i == 10)
   using (var cd = new CacheDependency(fi.FullName))
      if (cd.GetUniqueID() == null)
         throw new FileLoadException("Network drive out of sync with local view of it");

Upvotes: 0

theyetiman
theyetiman

Reputation: 8908

I can't explain why this happens, but I found that making the thread sleep for a very short period of time allows the file dependency manager to "get it's sh*t together" and acknowledge that the newly generated file actually exists before trying to create an eTag from it.

...<code to generate "filename" goes here>...

// BUG: For some reason, even though the cache file has definitely been created at this stage, the file dependency manager
// seems to require a bit of time to "register" that the file exists before we add it to the list of dependencies.
// If we don't tell the thread to sleep, we will get an error when it generates the eTag (no idea why this happens - can't find anything on the web).
// If the cache file already existed when this request began, then there is no error.
Thread.Sleep(5);
context.Response.AddFileDependency(filename);                
context.Response.Cache.SetLastModifiedFromFileDependencies();
context.Response.Cache.SetETagFromFileDependencies();
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetMaxAge(new TimeSpan(999,0,0,0));
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetValidUntilExpires(true);                
context.Response.Cache.VaryByParams["*"] = true;
byte[] buffer = File.ReadAllBytes(filename);
context.Response.ContentType = MimeMapping.GetMimeMapping(mi.Mi_filename);
context.Response.StatusCode = 200;
context.Response.BinaryWrite(buffer);

Upvotes: 7

Related Questions