11

I've read lots of posts about caching already, but none of them actually match my needs exactly. In my mvc 3 app I have an action method GetImage() that returns a File of image type. Then I use this method in a view to display image:

<img width="75" height="75" src="@Url.Action("GetImage", "Store", new {productId = item.ProductId})"/>

I want to cache images on a Server. So, what I've already tried:

1) to use OutputCacheAttribute:

    [HttpGet, OutputCache(Duration = 10, VaryByParam = "productId", Location = OutputCacheLocation.Server, NoStore = true)]
    public FileContentResult GetImage(int productId)
    {
        var p = _productRepository.GetProduct(productId);
        if (p != null)
        {
            if (System.IO.File.Exists(GetFullProductImagePath(productId)))
            {
                var image = Image.FromFile(GetFullProductImagePath(productId));
                return File(GetFileContents(image), "image/jpeg");
            }
        }
        var defaultPath = AppDomain.CurrentDomain.BaseDirectory +
                             ConfigurationManager.AppSettings["default-images-directory"];

        var defaultImage = Image.FromFile(Path.Combine(defaultPath, "DefaultProductImage.jpg"));
        return File(GetFileContents(defaultImage), "image/jpeg");
    }

Images are not cached (I get status: 200 OK)

2) to use the following Response.Cache methods in a GetImage() method:

    public FileContentResult GetImage(int productId)
    {
        Response.Cache.SetCacheability(HttpCacheability.Public);
        Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 10));
        Response.Cache.SetExpires(DateTime.Now.Add(new TimeSpan(0, 0, 0, 10)));
        Response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate");        
        // other code is the same
    }

Images are not cached

3) Here I get: 304 Not Modified, but the GetImage() method returns nothing (empty image)

    public FileContentResult GetImage(int productId)
    {
        Response.StatusCode = 304;
        Response.StatusDescription = "Not Modified";
        Response.AddHeader("Content-Length", "0");     
        // other code is the same
    }

Question: How to cache the output of this action method on a server?

Aleksei Chepovoi
  • 3,915
  • 8
  • 39
  • 77

1 Answers1

14

Try like this:

[HttpGet]
[OutputCache(
    Duration = 10, 
    VaryByParam = "productId", 
    Location = OutputCacheLocation.ServerAndClient)]
public ActionResult GetImage(string productId)
{
    ...
}

Things to notice: using OutputCacheLocation.ServerAndClient and gotten rid of NoStore = true.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • thanks, it works perfectly! But I don't get this: I can't just cache the image on a server or on a client separately? – Aleksei Chepovoi Feb 08 '13 at 10:02
  • 1
    But when you cache the image only on the server, this server is **ALWAYS** hit. The client hasn't cached the image and it doesn't have a copy of it. Where do you think the client will get this image from? That's why you get 200 status code. The difference is that your expensive controller action is not invoked on the server but the image is directly served from the cache to the client. – Darin Dimitrov Feb 08 '13 at 10:04
  • Do I need here VaryByParam="ProductId"? Seems like it doesn't affect the result? And, as I got it, "ServerAndClient" means that all users will get the same cached images? – Aleksei Chepovoi Feb 08 '13 at 10:09
  • You need the `VaryByParam` if you want the cache to vary by the `productId` parameter. The cache is stored on the server and on each client so every client will get the same image (varying by the `productId` parameter of course). – Darin Dimitrov Feb 08 '13 at 11:32
  • If you don't use the VaryByParam parameter, the users will get the same image for all the products. – Huseyin Yagli Jan 09 '15 at 08:03
  • +1, ok i had [this](http://stackoverflow.com/questions/35969498/iis-8-0-add-both-expires-header-and-cache-control) issue, so i have planned to use `OutputCache` to set Expires for images at least and it works but with [0.9 milliseconds](http://stackoverflow.com/a/1349318/2218697) delay. – Shaiju T Mar 16 '16 at 08:52