13

What I want to achieve is this. I want to give the user the ability to upload an image file, store the image in BLOB in SQL Server, and then use this image as a logo in other pages of the site.

I have done this by using

   Response.Clear();
   Response.ContentType = "image/pjpeg";
   Response.BinaryWrite(imageConents);
   Response.End();

but to do this, I use a User control in the place where I want to show the image. I want to do it if possible using an asp:Image control, or even a pure old html image control. Is this possible?

Dominik
  • 1,016
  • 11
  • 30
Nikos Steiakakis
  • 5,605
  • 7
  • 44
  • 54
  • If you're working with System.Drawing in ASP.NET, [read these pitfalls you need to avoid](http://nathanaeljones.com/163/20-image-resizing-pitfalls/). Alternatively, just use [my ImageResizing.Net](http://imageresizing.net) library to avoid all the GDI bugs, get an optimized SQL Blob reader, and an incredibly good disk caching system. – Lilith River Dec 09 '11 at 07:27
  • 1
    The following article will help you: [Auto-bind byte[] to asp:Image](http://www.codeproject.com/Tips/445876/Auto-bind-byte-to-asp-Image) – vitaly-t Sep 04 '12 at 13:21

6 Answers6

18

Add a 'Generic Handler' to your web project, name it something like Image.ashx. Implement it like this:

public class ImageHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        using(Image image = GetImage(context.Request.QueryString["ID"]))
        {    
            context.Response.ContentType = "image/jpeg";
            image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
        }
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}

Now just implement the GetImage method to load the image with the given ID, and you can use

<asp:Image runat="server" ImageUrl="~/Image.ashx?ID=myImageId" /> 

to display it. You might want to think about implementing some form of caching in the handler too. And remember if you want to change the image format to PNG, you need to use an intermediate MemoryStream (because PNGs require a seekable stream to be saved).

Fredrik Kalseth
  • 13,934
  • 4
  • 25
  • 17
  • I know this is old, but I think you have what I'm looking for here. I'm just missing the knowledge right now, to figure it out. I've got my handler written. Here it is http://pastebin.com/m75e17237 and I've got the call to that handler. It looks like this: http://pastebin.com/m63e1ebc3 But when the page loads, I just get the missing image little red X box. I've never used a handler before, so may be doing something wrong. One thing I notice is that if I set a breakpoint in the handler, it never gets there. Any advice would be awesome, if you get a chance. -Will – aape Aug 28 '09 at 15:07
  • @aape: did you register the handler in web.config? – Răzvan Flavius Panda Oct 05 '11 at 10:13
  • Trying to get an answer to my issue here, I have two images which I want to display on a view depending on whether a student is enrolled or not, This view I have is strongly typed, how can I get this to work? – user793468 Nov 08 '12 at 20:23
9

You can BASE64 encode the content of the image directly into the SRC attribute, however, I believe only Firefox will parse this back into an image.

What I typically do is a create a very lightweight HTTPHandler to serve the images:

using System;
using System.Web;

namespace Example
{  
    public class GetImage : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            if (context.Request.QueryString("id") != null)
            {
                Blob = GetBlobFromDataBase(id);
                context.Response.Clear();
                context.Response.ContentType = "image/pjpeg";
                context.Response.BinaryWrite(Blob);
                context.Response.End();
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

You can reference this directly in your img tag:

<img src="GetImage.ashx?id=111"/>

Or, you could even create a server control that does it for you:

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Example.WebControl
{

    [ToolboxData("<{0}:DatabaseImage runat=server></{0}:DatabaseImage>")]
    public class DatabaseImage : Control
    {

        public int DatabaseId
        {
            get
            {
                if (ViewState["DatabaseId" + this.ID] == null)
                    return 0;
                else
                    return ViewState["DataBaseId"];
            }
            set
            {
                ViewState["DatabaseId" + this.ID] = value;
            }
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write("<img src='getImage.ashx?id=" + this.DatabaseId + "'/>");
            base.RenderContents(output);
        }
    }
}

This could be used like

<cc:DatabaseImage id="db1" DatabaseId="123" runat="server/>

And of course, you could set the databaseId in the codebehind as needed.

FlySwat
  • 172,459
  • 74
  • 246
  • 311
5

You don't want to be serving blobs from a database without implementing client side caching.

You will need to handle the following headers to support client side caching:

  • ETag
  • Expires
  • Last-Modified
  • If-Match
  • If-None-Match
  • If-Modified-Since
  • If-Unmodified-Since
  • Unless-Modified-Since

For an http handler that does this, check out: http://code.google.com/p/talifun-web/wiki/StaticFileHandler

It has a nice helper to serve the content. It should be easy to pass in database stream to it. It also does server side caching which should help alleviate some of the pressure on the database.

If you ever decide to serve streaming content from the database, pdfs or large files the handler also supports 206 partial requests.

It also supports gzip and deflate compression.

These file types will benefit from further compression:

  • css, js, htm, html, swf, xml, xslt, txt
  • doc, xls, ppt

There are some file types that will not benefit from further compression:

  • pdf (causes problems with certain versions in IE and it is usually well compressed)
  • png, jpg, jpeg, gif, ico
  • wav, mp3, m4a, aac (wav is often compressed)
  • 3gp, 3g2, asf, avi, dv, flv, mov, mp4, mpg, mpeg, wmv
  • zip, rar, 7z, arj
Taliesin
  • 471
  • 7
  • 6
  • Wow! This question is more than a year old! Thanks for the answer, however I have resolved the issue! +1 for the well documented answer. – Nikos Steiakakis Feb 22 '10 at 13:41
  • Alternatively, you can cache to disk and allow IIS to handle ETag, Last-Modified, etc. Like [ImageResizing.net](http://imageresizing.net) does. IIS does have a good performance advantage over managed code for serving static files, even with an optimal .NET implementation. – Lilith River Dec 09 '11 at 07:24
  • Thats why I do my processing offline and in a scalable way. https://github.com/taliesins/talifun-commander – Taliesin Apr 20 '12 at 07:15
2

Using ASP.Net with MVC this is pretty forward easy. You code a controller with a method like this:

public FileContentResult Image(int id)
{
    //Get data from database. The Image BLOB is return like byte[]
    SomeLogic ItemsDB= new SomeLogic("[ImageId]=" + id.ToString());
    FileContentResult MyImage = null;
    if (ItemsDB.Count > 0)
    {
        MyImage= new FileContentResult(ItemsDB.Image, "image/jpg");
    }

    return MyImage;
}

In your ASP.NET Web View or in this example, in your ASP.NET Web Form you can fill an Image Control with the URL to your method like this:

            this.imgExample.ImageUrl = "~/Items/Image/" + MyItem.Id.ToString();
            this.imgExample.Height = new Unit(120);
            this.imgExample.Width = new Unit(120);

Voilá. Not HttpModules hassle was needed.

Fidel Orozco
  • 998
  • 11
  • 19
0

We actually just released some classes that help with exactly this kind of thing:

http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16449

Specifically, check out the DatabaseImage sample.

Brad Wilson
  • 67,914
  • 9
  • 74
  • 83
0

Add the code to a handler to return the image bytes with the appropriate mime-type. Then you can just add the url to your handler like it is an image. For example:

<img src="myhandler.ashx?imageid=5">  

Make sense?

Ryan Farley
  • 11,315
  • 4
  • 46
  • 43