Streaming byte[] to Image in ASP.NET C#
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);
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, 2020Comments
-
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 over 14 yearsDon't use ASPXs to output images, use an ashx.
-
LukeH over 14 yearsThis won't scale across a webfarm (unless you have some sort of distributed cache).
-
Dovi over 14 yearsNever ever do this. You're sacrificing all the goodness of HTTP (
If-Modified-Since
, caching, etc) and scalability for absolutely no benefits. -
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 anaspx
is no easier than creating anashx
anyway!) -
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 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 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 over 14 years@anton: did you see the commented line in my code? What do you think I mean by that?
-
AnthonyWJones over 14 yearsYou'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 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 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 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 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 over 14 yearsTrue 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 over 14 yearsI want to prevent another call to the database. I already have the data from my first call.
-
markoo over 14 yearsI already have the data from the database. I want to save another call.
-
markoo over 14 yearsThis 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 over 14 yearsThis 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 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 over 14 yearsYou 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 over 14 yearsThanks for the tip. I have tested in IE, FF, Chrome so far and it works fine even with images up to 400 KB
-
markoo over 14 yearsOk, 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 over 14 yearsOh no! I think it should work with smaller images, but that may not solve your problem :-(
-
Lilith River almost 13 yearsAn 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 almost 13 yearsMemcaching 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.