How to cache output of action method that returns image to the view in asp.net mvc?
Asked Answered
S

1

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?

Snailpaced answered 8/2, 2013 at 9:27 Comment(0)
S
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.

Samira answered 8/2, 2013 at 9:58 Comment(6)
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?Snailpaced
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.Samira
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?Snailpaced
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).Samira
If you don't use the VaryByParam parameter, the users will get the same image for all the products.Muliebrity
+1, ok i had this issue, so i have planned to use OutputCache to set Expires for images at least and it works but with 0.9 milliseconds delay.Petulant

© 2022 - 2024 — McMap. All rights reserved.