Dylan Beattie
Dylan Beattie

Reputation: 54150

Why can't I Response.Cache.SetLastModified in ASP.NET MVC 2 (and what is a "caching restrictiveness hierarchy" ?)

Trying to set cache response headers on a dynamically-generated image, I'm getting a weird error:

ArgumentOutOfRangeException was unhandled by user code

Specified argument was out of the range of valid values.

Parameter name: utcDate

I'm reading the file's last write time from a data cache, and then calling

Response.Cache.SetLastModified(lastWriteTime.Value.ToUniversalTime());

The last write time's value is {2011-07-25 18:09:56}, as I'd expect... I have no idea why this is going wrong.

The MSDN documentation for this method contains the rather cryptic statement (my emphasis):

The Last-Modified HTTP header time stamps the document with the DateTime value indicating when the document was last modified.

This method will fail if the caching restrictiveness hierarchy is violated.

SetLastModified is introduced in the .NET Framework version 3.5. For more information, see .NET Framework Versions and Dependencies.

What is a caching restrictiveness hierarchy? Am I violating one? If not, why is the last modified time being rejected?

Upvotes: 1

Views: 2203

Answers (1)

Robin Minto
Robin Minto

Reputation: 15367

SetLastModified will throw ArgumentOutOfRangeException if your lastWriteTime is in the future.

This will succeed:

var t1 = DateTime.Now;
Response.Cache.SetLastModified(t1);

This will fail:

var t2 = DateTime.Now + new TimeSpan(0, 0, 0, 1);
Response.Cache.SetLastModified(t2);

Decompiling System.Web illustrates this:

public void SetLastModified(DateTime date)
{
  this.UtcSetLastModified(DateTimeUtil.ConvertToUniversalTime(date));
}

private void UtcSetLastModified(DateTime utcDate)
{
  utcDate = new DateTime(utcDate.Ticks - utcDate.Ticks % 10000000L);
  if (utcDate > DateTime.UtcNow)
    throw new ArgumentOutOfRangeException("utcDate");
  if (this._isLastModifiedSet && !(utcDate > this._utcLastModified))
    return;
  this.Dirtied();
  this._utcLastModified = utcDate;
  this._isLastModifiedSet = true;
}

Are you generating the lastWriteTime on one server and then reading on another where there is a time discrepancy between the servers?

Some additional points:

  • You can also see that you don't need ToUniversalTime as the framework does that for you
  • Looks like the first line in UtcSetLastModified reduces precision
  • I can't tell you want a "caching restrictiveness hierarchy" is!

Upvotes: 6

Related Questions