views:

2387

answers:

5

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());
+1  A: 

create separate page where you will create image for example: image.aspx and use it on other pages

<img src="image.aspx?id=number" >

number is id of image in database

x2
Don't use ASPXs to output images, use an ashx.
AnthonyWJones
@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!)
LukeH
@Anthony: I dont know the differnece. It's only extension isn't it? It can be even number.jpg with routing.
x2
@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
@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
I want to prevent another call to the database. I already have the data from my first call.
markoo
+2  A: 

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);
AnthonyWJones
This won't scale across a webfarm (unless you have some sort of distributed cache).
LukeH
Never ever do this. You're sacrificing all the goodness of HTTP (`If-Modified-Since`, caching, etc) and scalability for absolutely no benefits.
Anton Gogolev
@anton: did you see the commented line in my code? What do you think I mean by that?
AnthonyWJones
@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.
AnthonyWJones
@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.)
LukeH
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.
AnthonyWJones
This seemed a very longwinded way of throwing my bytes about. It may well be the "correct" way, but not optimal in my situation also with maintenance in mind in the future. More lines of code => more chance of bugs.
markoo
A: 

You need an IHttpHander which will write image bytes and proper Content-Type to a response stream. See this, this and this.

Anton Gogolev
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
@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
@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
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
A: 

I'm pretty sure that you can't do this in the page itself.

If you don't want to create a HTTP Handler to output the image then your alternative is to create a separate aspx page. Set the src of your img tag to point at that page, passing some sort of ID in the querystring so that the image data can be pulled from the database.

Having said that, setting up an aspx page to do this is no quicker or easier than setting up an ashx. I would recommend doing this the right way and creating a HTTP Handler.

LukeH
I already have the data from the database. I want to save another call.
markoo
+2  A: 

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.

Rune Grimstad
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;
markoo
@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.
AnthonyWJones
My image ends up being around 8 KB, which in my simple user data view is quite acceptable. It is an "internal" admin site within my company. Although the actual component will be used externally. These external components and sites are heavily cached by our admins. So I have no worries in implementing this solution.These profiles are very limited. Only around 20 or 30 in house journalists. So it seemed overkill to have a separate image table just for these.Thanks again for your insight.
markoo
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.
Rune Grimstad
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
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!
markoo
Oh no! I think it should work with smaller images, but that may not solve your problem :-(
Rune Grimstad