Edited
I want to cache images on the client and know that there are different ways to do this in mvc 3: (correct me if I am wrong)
1) You can use OutputCacheAttribute , which works using the Expires http header. But it will return 304 Not Modified if the time does not expire (even if the image has been resized).
2) To avoid stale images, you can use the Last-Modified http header (with OutputCacheAttribute ). In this case, the browser sends a request to the server with the If-Modified-Since http header. On the server, you check whether the object remains valid or not, and if you simply return the Last-Modified http-header (and the browser takes an image from the local cache); if the object has been modified, you return it with a status of 200 OK .
Thus, the browser must send a request to the server each time before taking the image from its own cache. Here is an example -
3) There is another way (as I was told correctly in my case, because images will change very rarely ... in any case, I need to implement just that): To add the changed date to the image URL and set the caching with Expires for eternity (1 year or more). If the image has changed, you should send a new url with the new version.
Here is the code:
public class LastModifiedCacheAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.Result is FilePathResult) { var result = (FilePathResult)filterContext.Result; var lastModify = File.GetLastWriteTime(result.FileName); if (!HasModification(filterContext.RequestContext, lastModify)) filterContext.Result = NotModified(filterContext.RequestContext, lastModify); SetLastModifiedDate(filterContext.RequestContext, lastModify); } base.OnActionExecuted(filterContext); } private static void SetLastModifiedDate(RequestContext requestContext, DateTime modificationDate) { requestContext.HttpContext.Response.Cache.SetLastModified(modificationDate); } private static bool HasModification(RequestContext context, DateTime modificationDate) { var headerValue = context.HttpContext.Request.Headers["If-Modified-Since"]; if (headerValue == null) return true; var modifiedSince = DateTime.Parse(headerValue).ToLocalTime(); return modifiedSince < modificationDate; } private static ActionResult NotModified(RequestContext response, DateTime lastModificationDate) { response.HttpContext.Response.Cache.SetLastModified(lastModificationDate); return new HttpStatusCodeResult(304, "Page has not been modified"); } }
And I registered LastModifiedCacheAttribute in Global.asax and applied the following OutputCacheAttribute method to my action method.
[HttpGet, OutputCache(Duration = 3600, Location = OutputCacheLocation.Client, VaryByParam = "productId")] public FilePathResult GetImage(int productId) {
If I use the code above, it looks like the browser is not sending requests to the server, instead, it just takes images from the cache if the duration does not end. (When I change the image, the browser does not display the new version)
Questions:
1) . How to implement the third approach, so that the browser takes images from the client’s cache (and will not send a response to the server every time it wants an image), if only the image was changed?
edited: the actual code will be evaluated.
2) In the above code, the time of the first image request is recorded in Last-Modified (I don’t know why). How to write file modification date in Last-Modified?
edited: this question relates to the second approach. Also, if I only cache on the client and use the Last-Modified implementation, I only get the status 304 Not Modified if I press F5 . If I return to the same URL, I will get 200 OK . If I cache on the client without using Last-Modified , it will always return 200 OK no matter what. How can this be explained?