2

I have an MVC.net website which serves images based on this old article:

http://blogs.msdn.com/b/miah/archive/2008/11/13/extending-mvc-returning-an-image-from-a-controller-action.aspx

My c# controller code looks like this:

public ActionResult GetThumbnail(string code)
{
    byte[] image = _dataProvider.GetThumbnailImage(code);
    return this.Image(image, "image/jpeg");
}

On the client side I have an AngularJS controller which loads up a search result set from the server. The result set includes a number of image URLs like this:

    <tr ng-repeat="item in data.items | filter:filter" class="fixed-height-80">
        <td>
            <a href="{{ item.viewDetailUrl }}"><img ng-src="{{item.thumbnailUrl}}"/></a>
        </td>
    </tr>

The thumbnailUrl points to the GetThumbnail action on my MVC controller and is constructed server side in a model factory and returned to the Angular ready for use.

The problem is that the images load very slowly even thought they are only about 3kb per image. After the async search return is completed in the javascript the images appear one at a time, about one per second, until they are all loaded.

I put a Stopwatch in the C# on the .net controller and the loading of the image data from the dataProvider on the server side takes about 0.9ms But even with just ten images to serve it takes about six seconds before all the images are loaded in the page. The JS renders the links almost immedialtly, it's just the images that are slow.

How can I speed up image loading in this context?

Update

If I move the images into ~/images/image.jpg and route the url to point directly at the folder using Url.Content it doesn't seem to have the same issue. therefore the problem seems to be with the way the controller is serving the images - sometimes if can take < 10ms and other times over 2000ms for the same image, but it's unclear why.

7
  • How large are the image files? Commented Nov 24, 2014 at 9:48
  • Are the images generated, altered or just fetched? In the last scenario, the whole thing can possibly be split into using backend code for getting file names, and browser loading images from a static directory. Commented Nov 24, 2014 at 9:52
  • The images files are approx 3kb and if loaded direct on the page they load almost at once. Commented Nov 24, 2014 at 10:06
  • 1
    Can you use Profiler, like Miniprofiler to check where's the bottleneck? Commented Nov 24, 2014 at 11:20
  • @MaxBrodin - interesting results - there are multiple calls to /GetThumbnail (one for each image as you'd expect) - about half are processing in ~10ms (6.2 -> 13.8) which is what I'd want, but others are taking over two seconds (2047.7 -> 2564.2) - the images are similar sizes and going through the same route. Commented Nov 24, 2014 at 11:43

4 Answers 4

3

Several options are available:

  1. Caching the images in the browser/client-side by adding cache-control HTTP to the response headers.
  2. Caching the images in the server-side (in-memory) instead of carrying-out an I/O operation to the file-system (IIS will cache frequently used images and serving them from memory).
  3. Compression of HTTP response's resources using GZIP, for example (you should do it in your Web-Server).
  4. Reduce images size/quality in the server (maybe while uploading them).
  5. Use CSS image sprite technique: An image sprite is a collection of images put into a single image and by that, reducing the number of images that the browser need to load.
  6. Use a dedicated CDN for serving your images faster and in turn, reduce the load-time on the server.

You should decide what's the best choice in your case.

UPDATE:

Another 2 options:

  1. With ng-repeat, in each iteration of your results you're effectively accessing the server instead of accessing the browser cache - there could be hundreds of records. It would be better to send your images with cache-control HTTP response headers (A Beginner's Guide to HTTP Cache Headers) in order to prevent accessing the server again and again for fetching the images and reducing the repeated round-trips.

  2. Pre-load your images into the browser cache: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

Sign up to request clarification or add additional context in comments.

3 Comments

1. Already doing this, but it doesn't help with first page load. 2. already doing this, but server side loading isn't a significant time factor. 3. Already doing this. 4. Images are already sized and compressed. 5. I'm not sure this is useful for search results as you'd have to build a new sprite for each return. 6. although this may bypass the issue I'm pretty sure a CDN server shouldn't be required to serve a 3kb image unless the server load is very high.
I'm not sure this is a cache type issue - once the images have been loaded once the browser cache works well and the images are not repeately requested. However, on the initial page load (after flushing all the cache for testing) the image loads are very slow, even on my localhost version of the site where internet speed isn't an issue. I'm sure this shouln't be the case - the other images on the same page that are not loaded via angualr (but ARE loaded by the same MVC controller) do not have this issue.
A CDN should slightly speed it up, try using cloudfront from amazon. Its free for most websites unless you are really really big aws.amazon.com/cloudfront
1

Consider option to resize images once they loaded on the server and store thumbnails images on the server or CDN as well as orignal version. This will reduce server load and make image load as fast as getting image without any processing every time image requested.

3 Comments

Generally good advice, however in this case the images files are already compressed thumbnails (approx 3kb per file) and if loaded direct on the page they load almost at once. The server side code is simply a single select on a db to get the filename and then a File.LoadAllBytes call to get the file contents. As noted in the question, the serverside code runs in less than a milisecond.
I wonder why do you need to read the thumbnail image data and return image result instead of just include thumbnailUrl in your item model, so in the end you will have thumbnailUrl to point to thumbnail image itself?
Because the actual image files are outside the root of the website directory on the server - this is because the images are shared across more than one site. In the future they may also be server direct from the DB.
0

Use a proper CDN or just serve it directly from virtual directories. Your current implementation is IIS is good and fast as a web server, .Net framework is good as a server-side technology.

A properly configured IIS will help you save bandwidth and file system I/O, if you need resizing capabilities, check out Image Resizer

Comments

0

It turns out that it's the MVC SessionState that causes this issue - although it's not entirely clear why at thgis stage.

Adding a new controller just for images and decorating it as below will disable the default session state behaviour and prevent the images getting stuck 'waiting' for ages.

    [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
    public class ImageController : Controller
    {
      public ActionResult GetThumbnail(string code)
      {
          byte[] image = _dataProvider.GetThumbnailImage(code);
          return this.Image(image, "image/jpeg");
      }
    }

Comments

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.