Streaming byte[] to Image in ASP.NET C#

20,023

Solution 1

If it is a small image you would output it as base64 encoded data into an image-tag. See here for a similar situation.

But in 99.9% of all situations you would create a HttpHandler that returns the image. It is the easiest and fastest way to do it I think.

Solution 2

Wrap the byte array in a MemoryStream object and place that in ASP.NETs Cache.

MemoryStream ms = new MemoryStream(user.Picture.ToArray());
Guid imageGuid = new Guid();
HttpRuntime.Cache.Add(imageGuid.ToString(), ms, null,
    DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

Then use a handler (.ashx) to fetch it out of the cache and send it to the client.

string imageGuid = context.Request.QueryString[image];
MemoryStream ms = (MemoryStream)HttpRuntime.Cache[imageGuid];
// configure context.Response with appropriate content type and cache settings

// ** Edit **
// It seems I need to be more explicit with regard to the above comment:-
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetLastModified(DateTime.UtcNow);
context.Response.Cache.SetExpires(DateTime.UtcNow.AddHours(2);
context.Response.Cache.SetMaxAge(TimeSpan.FromHours(2));
context.Response.Cache.SetValidUntilExpires(true);

ms.WriteTo(context.Response.OutputStream);

Now you can drop the MemoryStream from the Cache.

HttpRuntime.Cache.Remove(imageGuid);
Share:
20,023
markoo
Author by

markoo

.NET & ASP.NET developer since 2005. Previously JAVA developer 2000 - 2005. Developer of LiveFootie ViewSource Champions League Final UEFA Euro 2012 on the Windows Phone Marketplace.

Updated on March 30, 2020

Comments

  • markoo
    markoo about 4 years

    I have an Image stored in my SQL Server database stored with my User data which I retrieve all at once.

    Now I have the byte[] directly on the page I want to show it on. How do I put it in my WebControls.Image? I don't want to have to call an HttpHandler and call the database again.

    This obviously just outputs it to the whole page.

                Context.Response.BinaryWrite(user.Picture.ToArray());
    
  • AnthonyWJones
    AnthonyWJones over 14 years
    Don't use ASPXs to output images, use an ashx.
  • LukeH
    LukeH over 14 years
    This won't scale across a webfarm (unless you have some sort of distributed cache).
  • Dovi
    Dovi over 14 years
    Never ever do this. You're sacrificing all the goodness of HTTP (If-Modified-Since, caching, etc) and scalability for absolutely no benefits.
  • LukeH
    LukeH over 14 years
    @Anthony: The OP says they don't want to use an ashx, although I agree that it's the right way to do this. (And creating an aspx is no easier than creating an ashx anyway!)
  • x2.
    x2. over 14 years
    @Anthony: I dont know the differnece. It's only extension isn't it? It can be even number.jpg with routing.
  • AnthonyWJones
    AnthonyWJones over 14 years
    @x2: There is a reason why MS describes the ASPX file as a ASP.NET Form. It comes with a considerable overhead associated with a full form lifecycle (intialiseing controls, loading them, handling post back, pre-render, render, unloading, disposing blah blah). None of which you need if all you are going to do is tweak up the properties of a the response object and dump a chunk of data in the output. In that case .ashx is way easier and cleaner solution.
  • AnthonyWJones
    AnthonyWJones over 14 years
    @Luke: The reason the OP wanted to avoid a handler is to avoid having to read the picture out of the DB again, I don't read it an aversion to handlers per-se, just an avoidance of needlessly duplicating a significant operation.
  • AnthonyWJones
    AnthonyWJones over 14 years
    @anton: did you see the commented line in my code? What do you think I mean by that?
  • AnthonyWJones
    AnthonyWJones over 14 years
    You've missed the point in the Question. Given that you have in an executing ASPX page a byte array of image data acquired from a database how would you get an <img on in the output to display that image without re-querying the DB??
  • AnthonyWJones
    AnthonyWJones over 14 years
    @Luke: on the contrary making good use of a web farm is exactly what using the cache is good for. In a WLB environment the session can and most often is affiliated with a server in the farm. The whole point of having a Web Farm is to take the pressure of the database tier and caching is a very important part of that solution.
  • LukeH
    LukeH over 14 years
    @Anthony: Surely the point is that he doesn't need to pull the image data out of the database on the page itself. He doesn't need to re-query the database - he needs to query it once at the appropriate place/time (ie, in a separate ashx handler.)
  • LukeH
    LukeH over 14 years
    @Anthony: The built-in ASP.NET cache, as used in your example code, is not distributed: each webserver has its own cache. If your image request hits a different server then the image data won't be found in its cache. (Obviously this doesn't apply if your webfarm uses sticky sessions, but that has its own scalability issues.)
  • AnthonyWJones
    AnthonyWJones over 14 years
    @Luke: That may be, but we don't know that do we? All we have from the question is that for some reason he has an object which already has a loaded Picture object. Perhaps that can be avoided better yet place the picture in the file system. I prefer to answer the question at hand especially since some other SO user may find at some point they are in this situation for unavoidable reasons.
  • AnthonyWJones
    AnthonyWJones over 14 years
    True if it hits a different server. However it is not a requirement for good answers to also remain true when extreme scalability is required. Web farm compatiblity sans sticky sessions was not specified in the question. Consider also that this answer is the only one addresses the specific question asked. Ordinarily you would at this point have expected the OP to have stepped in to clarify things in which case this answer may be defunct but right now that is not so. The OP may be buildng a small Intranet in which case worrying about web farms would be a waste of time.
  • markoo
    markoo over 14 years
    I want to prevent another call to the database. I already have the data from my first call.
  • markoo
    markoo over 14 years
    I already have the data from the database. I want to save another call.
  • markoo
    markoo over 14 years
    This was also the only solution I found on Google, but of no use to me, as I already have the data from the database once, and don't want to waste another call.
  • markoo
    markoo over 14 years
    This was exactly what I was looking for. The image is a small 180 x 160 px gif/jpeg. It ended up like this: byte[] picByteArray = user.Picture.ToArray(); string myPicString = Convert.ToBase64String(picByteArray); myPicture.Attributes["src"] = "data:image/gif;base64," + myPicString;
  • AnthonyWJones
    AnthonyWJones over 14 years
    @Markoo: How many bytes does that end up being when base64 encoded? By placing the image data directly in the dynmically generated HTML you require the client to fetch it every time, it isn't cacheable unless you make the entire html response cacheable.
  • Rune Grimstad
    Rune Grimstad over 14 years
    You should be careful that not all browsers can read that much data when stored inline. Be sure to test the page properly in all the browsers you support.
  • markoo
    markoo over 14 years
    Thanks for the tip. I have tested in IE, FF, Chrome so far and it works fine even with images up to 400 KB
  • markoo
    markoo over 14 years
    Ok, just found out this doesn't work in IE pre8, because I have IE8 on my dev machine, but our in-house users don't yet! Aaargh!
  • Rune Grimstad
    Rune Grimstad over 14 years
    Oh no! I think it should work with smaller images, but that may not solve your problem :-(
  • Lilith River
    Lilith River almost 13 years
    An VirtualPathProvider is even better, since you don't have to re-implement all the HTTP support in your HttpHeader. I wrote a SqlReader provider that does just that, and it's very easy to set up.
  • Lilith River
    Lilith River almost 13 years
    Memcaching images doesn't work well - they're rarely updated, and lost every reboot. And you'll need a heck of a lot of RAM. Disk caching is better, and gives you kernel-mode speeds.