5

I'm programming an ASP.NET MVC4 application which stores uploaded images as byte[] in a database (with Entity framework) and then displays them. To display the images I'm using this code in the view:

<img src="data:image;base64,@System.Convert.ToBase64String(item.ImageByte)" alt=""/>

But each time I refresh the page I see that the browser does not cache the image and just renders it again causing unecessary bandwith usage.

Maybe there's a more bandwith friendlier way to display the image? Maybe the idea to store uploaded image as 'byte[]' was stupid in the first place (my application is just a simple web page which stores articles about psychology :D with an admin panel to achieve this) and I should just store images in a folder?

Thanks

3
  • as a side note. dont store images as blobs in the database, it makes your database slow and completely inefficient. only store the filenames of the images in the database and store the files in a directory on disk Commented Aug 9, 2013 at 21:06
  • @bizzehdee there are times when what you say is true. For small amounts of data I think it's an acceptable usage to store images in a db. As long as you realize that it isn't really suitable for a medium to large system Commented Aug 9, 2013 at 21:10
  • @bizzehdee - there are already many questions on "files in DB" subject (like stackoverflow.com/questions/3748/…) with generally less absolute black and whit approach. I.e. "upload user image to site with 5 front end machines" - you get significantly simple system with images in DB compared to custom-build file storage, not necessary faster but it is rarely the main goal. Commented Aug 9, 2013 at 21:30

3 Answers 3

5

Storing the image in the database is one possible option. There are times when it is a good idea, and times when a bad idea. Generally if dealing with large amounts or large sized images you may be advised to reconsider using a different storage method.

Effectively what you're currently doing is embedding the image in the HTML; this can be good I've used it before when it would take around 5 seconds to calculate the data for a graph and the same data is required for the page, but in general usage you'd be better off serving the image from an action.

So what we need to do is to provide an action in a controller to get the image; probably based on id - but that I'll leave up to you.

[OutputCache(Duration = 3600, VaryByParam = "id")]
public ActionResult GetImage(int Id)
{
    // 1. provide connection to entity framework
    var dbc = new DatabaseContext();
    var item = dbc.FindItem(Id);// call to get the image from EF (2)
    var ms = new MemoryStream(tem.ImageByte);    
    FileStreamResult result = new FileStreamResult(ms, "image/png");
    result.FileDownloadName = item.ImageName; // or item.Id or something (3)
    return result;
}

in the cshtml

<img src="@Url.Action("GetImage", "Controller", new {Id = Model.ImageId})" />

So in the above code you need to provide

  1. The connection to EF
  2. the call to locate the image
  3. something for the image name
  4. possibly change the output cache
Sign up to request clarification or add additional context in comments.

2 Comments

the times that it is a good idea are: "never" and "sometime after hell freezes over". times when its a bad idea are "now" and "always"
@bizzehdee For small sites it's probably a bad idea, but "images shouldn't go in databases" is far from a universally true statement.
3

In your HomeController add a function like this:

[HttpGet]
public FileResult GetImage(string id)
{
    byte[] fileContents = ...; // load from database or file system
    string contentType = "image/jpeg";
    return File(fileContents, contentType);
}

Register a route to this handler in Global.asax.cs:

routes.MapRoute(
    "GetImage",
    "img/{id}",
    new { controller = "Home", action = "GetImage" });

In your webpage, use a src pointing to this action:

<img src="@Url.Action("GetImage", "Home", new { id = "logo.jpg" })" />

which will resolve to

<img src="/img/logo.jpg" />

2 Comments

Thanks. I've implemented this approach without registering the route- I don't know the purpose of routing in this scenario (I'm new on MVC).
@Nmktronas Glad it worked for you. The purpose of registering the route is purely to make the URL prettier. There's zero value in terms of functionality. That being said, it is a good habit to get into, because it helps to decouple the API you expose to users (in terms of URLs and actions on URLs) from the controllers, actions, etc. If you use the default routing, the URL will be /Home/GetImage/logo.jpg, and if you want to, say, change the name of the GetImage method, you'll be changing the API too.
2

add Generic Handler

public class Handler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        long id = Convert.ToInt64(System.Web.HttpContext.Current.Request.QueryString["id"]);
        string model = (System.Web.HttpContext.Current.Request.QueryString["model"]);
        DbContext Db = new DbContext();
        byte[] picture = new byte[0];

        switch (model)
        {
            case "News":
                NameSpace.Models.News news = Db.Newss.Single<NameSpace.Models.News>(n => n.ID == id);
                picture = news.Picture;
                break;

            case "Article":
                NameSpace.Models.Article article = Db.Articles.Single<NameSpace.Models.Article>(a => a.ID == id);
                picture = article.Picture;
                break;
        }

        context.Response.Clear();
        context.Response.ContentType = "image/jpeg";
        context.Response.BinaryWrite(picture);
        context.Response.Flush();
        context.Response.End();
    }

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

*and in view use this sorce for image img src="/Handlers/[email protected]&model=News"

3 Comments

I was just typing a similar solution when I saw Saman's answer pop up. An http handler is the way to go. The only thing I'd add is that you'll have to do some routing work to get MVC to ignore calls to Handler.ashx.
Why is this getting so many upvotes? This is anything but the MVC 3+ way to do things...
+0: while it is valid approach dropping all features MVC gives you (much better testability, like model binding, action attributes/global filters, ease of dependency injection...) is questionable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.