4

I'm currently trying to view images that are stored in a database as BLOBs, to do that I've created a Controller Action of the type FileContentResult which looks like this:

public FileContentResult ImageFile(string imageId)
    {
        var client = new WcfTestClient();

        DataTable table = client.GetImageData(imageId);
        var image = ConvertToBytes(table);
        byte[] bytes;

        bytes = image[0].Values.ElementAt(0);

        return File(bytes, @"image/png");
    }

It gets the correct image data from the database and ConvertToBytes() works correctly as well but for some reason, after returning the image to the View it jumps back to the top and runs again.

I'm using Ajax to call the method from my View like this:

$.ajax({
    url: "/Home/ImageFile",
    type: "GET",
    data: { "imageId": imageId },
    success: function (data) {
        var image = document.createElement('img');
        image.src = "/Home/ImageFile?id=" + imageId;
        image.width = 100;
        image.height = 100;
        div.appendChild(image);
    }
});

Does anyone know what might cause my problem?

Update

Okay, so now after being told that it was Ajax that messed it up I've tried to send a parameter to my Controller Action like this:

var images = JSON.parse(window.localStorage.getItem("JsonImages"));
var div = document.getElementById('imgOutput');

for (var i = 0; i < images.length; i++) {
    var imageId = images[i].pi_Id;
    var imgId = JSON.parse('{"imageId":' + imageId + '}');

    var img = document.createElement('img');
    img.src = "/Home/ImageFile?id=" + imgId;
    img.width = 100;
    img.height = 100;
    div.appendChild(img);
}

Which, sadly, doesn't work very well. So, is there a way to send a parameter to ImageFile() without making it run twice? Am I missing something fundamental here?

Update 2

Finally I got it to work! This is how it looks now:

var images = JSON.parse(window.localStorage.getItem("JsonImages"));
var div = document.getElementById('imgOutput');

var createImage = function (src) {
    var img = document.createElement('img');
    img.src = src;
    img.height = 100;
    img.width = 100;
    return img;
}

for (var i = 0; i < images.length; i++) {
    var imageId = images[i].pi_Id;
    var imageSrc = "/Home/ImageFile?imageId=" + imageId;
    div.appendChild(createImage(imageSrc));
}

I just needed to change the source's parameter from id to imageId (duh). Thank you for all your help!

tereško
  • 58,060
  • 25
  • 98
  • 150
Erik Karlstrand
  • 1,479
  • 9
  • 22

1 Answers1

6

The problem is that you first issue an AJAX request to the ImageFile controller action, then, when it returns the result successfully, you create a DOM element which references that same route, so the browser issues another request in its attempt to create the image tag.

You don't need that AJAX call at all, by the looks of it. If you simply create the image tag with the route of the action as the src, it should work. Pull your success callback out of the AJAX request and just use that on its own.

Alternatively, if you're not doing anything particularly dynamic, you can just use the route directly in your image src tag and not use Javascript at all. For example, if you're working with Razor:

<image src="@(String.Format("/Home/ImageFile?id={0}", Model.MyImage))"
    height="100" width="100" />

If it needs to be dynamic and Javascript based, you can just drop the AJAX, because you don't need it:

function createImage(src, width, height) {
    var img = document.createElement('img');
    img.src = src;
    img.height = height;
    img.width = width;
    return img;
}

var someId = /* Whatever your ID is */;
var imgSrc = "/Home/ImageFile?id=" + someId;
div.appendChild(createImage(imgSrc, 100, 100));
Ant P
  • 24,820
  • 5
  • 68
  • 105
  • Okay, I did this before and it worked well when I didn't have to send a parameter back to ImageFile. I tried this now to get all images that are connected to a user by setting img.src = "/Home/ImageFile?id=" + { "imageId": imageId }; but now the ID is not sent as a parameter. Any ideas? – Erik Karlstrand May 03 '13 at 07:17
  • Can you post the whole snippet as an update to your question? It's difficult to tell what you're doing there. – Ant P May 03 '13 at 07:39
  • It needs to be dynamic and I want to do as little as possible server-side. The end product is meant to be used by a company's customers and they should be able to work offline if needed. I'm simply trying to figure out a way to load all the images the customer needs all at once so that they can be loaded from the cache later. So my question is: Can I send a parameter to my Controller Action without using $.ajax(), $.post() or any similar methods that will cause the FileContentResult to run twice? Am I missing something? – Erik Karlstrand May 03 '13 at 07:39
  • @noMad17 Please see my update - does this make it any clearer? – Ant P May 03 '13 at 07:46
  • You don't need that AJAX.. Also, if the application is to be used offline I would seriously look at other options. – BenjaminPaul May 03 '13 at 07:47
  • @AntP sadly it still doesn't send the imageId as a parameter to ImageFile. I've fetched the Id of all images connected to the user and saved them in localStorage as a JSON string. I now want to iterate over this string and fetch the actual images from the database. – Erik Karlstrand May 03 '13 at 07:59
  • To be honest it sounds like your problem is elsewhere. Can you debug through your Javascript and make sure that `imgId` actually gets a value? If it doesn't you have a separate issue that's stopping it from getting this far (which should probably be a separate question as this comment string is getting lengthy). – Ant P May 03 '13 at 08:03