2

I'm having a hard time figuring out on how to cache the image from a blob stream.
This is my first code and it works to download the return the image file:

HTML PART:

<img src="@Url.Action("GetImage", "Asset")?photoId=@SessionData.ProfilePic.PhotoID&type=3"/>  

CONTROLLER:

public ActionResult GetImage(long photoId, PhotoType type)
{   
    byte[] img = <Code that fetches image byte from blob stream>;
    return File(img, "image/png");            
}

But this fail to cache in browser.
I am thinking that if the url seems to be like this:

http://stackoverflow.com/Asset/GetImage/1/2  

the image can now be cache?
So I create another route:

routes.MapRoute(
    "Upload",
    "Asset/GetImage/{photoId}/{type}",
    new { controller = "Asset", action = "GetImage" }
);

and access the image like this:

http://stackoverflow.com/Asset/GetImage/1/2
<img src="http://stackoverflow.com/Asset/GetImage/1/2" />

But I always get:

Failed to load resource: the server responded with a status of 404 (Not Found)   

Now my questions are:

  1. Am I right of thinking that when the url is formatted like this http://stackoverflow.com/Asset/GetImage/1/2 it can now be cache by the browser?
  2. Why do I get this error? Failed to load resource: the server responded with a status of 404 (Not Found) What's wrong with my route?

Hope someone could help.

EDIT

This is my full Routes:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
    "Upload",
    "Asset/GetImage/{photoId}/{type}",
    new { controller = "Asset", action = "GetImage" }
);

var route = routes.MapRoute(
        "Gallery",
        "",
        new { controller = "Auth", action = "Login" },
        new[] { "Project.Areas.Gallery.Controllers" }
    );

route.DataTokens["area"] = "Gallery";  

And still getting the error Failed to load resource: the server responded with a status of 404 (Not Found) , what could be wrong ?

EDIT2

The list of meta tags I've used:

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="imagetoolbar" content="false">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
fiberOptics
  • 6,955
  • 25
  • 70
  • 105
  • Regarding the caching have you tried the OutputCache attirbute against the controller action methods? http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/improving-performance-with-output-caching-cs – Chris Moutray Aug 01 '12 at 04:41
  • Yes, I have tried that. But no luck. – fiberOptics Aug 01 '12 at 04:42
  • Does it work when you access the image directly? ie using http://yourserver/Asset/GetImage/1/2 – Chris Moutray Aug 01 '12 at 04:53
  • No. Because the params`(1/2)` are keys to reference from database, then used to download the image byte from blob via stream. There is not direct link to the image file. – fiberOptics Aug 01 '12 at 04:56
  • I think it should work - I've created a simple example using your example code and both direct url and image tag work - even by adding OutputCache attribute I can confirm caching now works – Chris Moutray Aug 01 '12 at 05:01
  • So can you confirm that an exception isn't being thrown from your controller method GetImage? – Chris Moutray Aug 01 '12 at 05:04
  • Can I see your headers? I'm trying again the OutpuCache. My headers look like this: Cache-Control: no-cache, Expires: -1, Pragma: no-cache. This is the code: [OutputCache(Duration = 10)] – fiberOptics Aug 01 '12 at 05:05
  • @ChrisMoutray There is no any exception thrown. I'm putting break points in every block of code and didn't encounter any error. – fiberOptics Aug 01 '12 at 05:24
  • From what I can tell 404 are common when routes don't match but you've said that breakpoint is hit within the GetImage method. – Chris Moutray Aug 01 '12 at 05:59
  • Sorry to confuse you, I put break points on GetImage Action method, I don't get any error because it doesn't even pass the break point. Please see my edit. Thanks! – fiberOptics Aug 01 '12 at 06:12
  • Still a little confused your edit to the question and comments here say your GetImage isn't working, but against my answer your comments suggest it is work just that the cache isn't working ie every request to /Asset/GetImage/#/# goes through your GetImage action method - can you clarify? Thanks. – Chris Moutray Aug 01 '12 at 08:12
  • I manage to make the link work. Now my problem is the caching. The image is not being cached. I wonder how you did it successfully while we have the same code, `[OutputCache(Duration = 20, VaryByParam = "photoId")]`. Thanks – fiberOptics Aug 02 '12 at 02:15
  • See edit to answer - can you comment on the whether you've tried to disable caching somewhere? If remove the attribute i see `Cache-Control: private` in the header and not `Cache-Control: no-cache` – Chris Moutray Aug 02 '12 at 05:31

1 Answers1

2

The following works for me

Action Method

[OutputCache(Duration = 20, VaryByParam = "photoId")]
public ActionResult GetImage(long photoId, long type)
{
    byte[] img = System.IO.File.ReadAllBytes(Server.MapPath("~/Images/aspNetHome.png"));
    return File(img, "image/png");
}

HTML

<img src="~/Home/GetImage/1/2" alt="" />

Route added to Global asax

routes.MapRoute(
    "Upload",
    "Home/GetImage/{photoId}/{type}",
    new { controller = "Home", action = "GetImage" }
);

Response headers from Fiddler

Referer: http:// localhost /MvcApplicationImageTest/Home/GetImage/1/2*

HTTP/1.1 200 OK
Cache-Control: private, max-age=20
Content-Type: image/png
Expires: Wed, 01 Aug 2012 05:08:25 GMT
Last-Modified: Wed, 01 Aug 2012 05:08:05 GMT
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 01 Aug 2012 05:08:10 GMT
Content-Length: 3736

EDIT following comments

OutputCacheAttribute removed

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: image/png
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 02 Aug 2012 04:52:02 GMT
Content-Length: 3736

As you can see in the headers, Cache-Control just shows private and not Cache-Control: no-cache, Expires: -1, Pragma: no-cache

I now believe you must be explicitly disabling the cache somehow? Do you have any META tags in your view or layout pages? eg

<meta http-equiv="cache-control" content="no-cache" />

<meta http-equiv="pragma" content="no-cache" />

<meta http-equiv="expires" content="-1" />
Chris Moutray
  • 18,029
  • 7
  • 45
  • 66
  • if I use this link: `` then I am now able to download the byte[]. But still even if I put your code: `[OutputCache(Duration = 20, VaryByParam = "photoId")]` it is not cached. Fiddler gives this result: Cache-Control: no-cache, Expires: -1, Pragma: no-cache – fiberOptics Aug 01 '12 at 06:21
  • I have managed to make the link work: `` but still the image is not cached. Please help. thanks – fiberOptics Aug 01 '12 at 07:03
  • No reason to read all the bytes into your code, just use this instead: `return new FilePathResult(Server.MapPath("~/Images/aspNetHome.png"), "image/png");` – Steen Tøttrup Aug 02 '12 at 05:10
  • Sure, but it's always good to suggest improvements in general I think. – Steen Tøttrup Aug 02 '12 at 05:14
  • @SteenT actually `Controller.File` has an overload that accepts a file path http://stackoverflow.com/questions/1187261/whats-the-difference-between-the-four-file-results-in-asp-net-mvc – Chris Moutray Aug 02 '12 at 05:20
  • @ChrisMoutray I have listed all meta tags that I use. Please see my **EDIT2** – fiberOptics Aug 02 '12 at 09:36
  • @ChrisMoutray I voted up your answer since your code works on new mvc project. But still I can't figure out why it doesn't work on the real one. Anyway thanks for your help. – fiberOptics Aug 07 '12 at 05:56
  • @fiberOptics its difficult to tell whats wrong with your original project - there must be other config somewhere eg web.config or in the global.ascx – Chris Moutray Aug 07 '12 at 06:28
  • What can i do when i use remote url like cdn? – Can Ürek Jan 24 '18 at 07:43
  • 1
    @CanÜrek I think you need to look at cdn provider to see if there are any cache options. Or you somehow route the cdn url through your api but that would defeat the point of the cdn - so I wouldn't recommend that. – Chris Moutray Jan 24 '18 at 09:32
  • Thanks for your responses. I handle it like that https://stackoverflow.com/questions/9164333/asp-net-mvc-returning-a-cdn-images-from-controller – Can Ürek Jan 24 '18 at 09:36