简体   繁体   中英

MVC4 Image optimization caching on demand performance issues

THE QUESTION Is there some .net , ASP , MVC or even IIS optimizations I'm not taking in account? or is this whole approach simply a bad idea ?

SCENARIO

The following works 0K

I have an ImageController that allows me to optimize and cache images on the fly.

The actual call looks like this: /image/user/1?width=200&height=200

And the controller itself like this:

[AllowAnonymous] // TODO author/revise
public class ImageController : FileController
{
    private FileResult Image(string entity, long id, int? width, int? height, Position? position=null)
    {
        string file = base.ImageHandler.ImagesPaths(Paths.img, entity, id.ToString()).FirstOrDefault();
        if (string.IsNullOrEmpty(file))
        {
throw new HttpException(404, "File not found");
        }

    // implicit else
        string extension = Path.GetExtension(file);
        System.Drawing.Imaging.ImageFormat oImageFormat = WebFileSystemImageHandler.ImageFormat(extension);

        if ((null != width) || (null != height))
        {
// vvv Beginning of IS THERE SOMETHING WRONG WITH THIS? vvv
            string path       = string.Format("{0}{1}/{2}/", Paths.img, entity, id);
            string pathServer = Server.MapPath(path);
            if (!Directory.Exists(pathServer))
                 Directory.CreateDirectory(pathServer);

            string pattern = "";
            if (null != width ) pattern += width.ToString();        // 500
            if (null != height) pattern += "x" + height.ToString(); // 500x400, or x400 w/o width

            string cache = Directory.GetFiles(pathServer, pattern).FirstOrDefault();
// ^^^ End of IS THERE SOMETHING WRONG WITH THE ABOVE ^^^
            if (string.IsNullOrEmpty(cache))
            {// no cache? sure let's get you started!
                Image oImage = System.Drawing.Image.FromStream(  new MemoryStream( System.IO.File.ReadAllBytes(file) )  );
                file = Server.MapPath(path + pattern + extension);
                Bitmap oBitmap = new Bitmap(oImage);
                       oBitmap = oBitmap.Adjust(width:width, height:height, position:position);
                       oBitmap = oBitmap.Compress();
                       oBitmap.Save(file, oImageFormat);
            }
            else
                file = cache;
        }
        MemoryStream oStream = new MemoryStream( System.IO.File.ReadAllBytes(file) );
        string mime = string.Format("image/{0}", extension.Replace(".", ""));
    return new FileContentResult(oStream.ToArray(), mime);
    }

Where base.ImageHandler.ImagesPaths basically returns a Directory.GetFiles("{folder}\\{entity}\\", "{id}.*").FirstOrDefault()

THE PROBLEM When I have a gallery page with multiple of these images, the html renders immediately but the images show empty and start popping 1 by 1 (I imagine this is due to 1 call to the controller per session). I would expect this as expected behavior the 1st run only , but happens every time

I wouldn't advise you use GDI for image resizing at all in MVC, as it's not supported and can cause memory leaks and other issues if not used carefully (see http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx ).

You should look at alternatives such as using Windows Imaging Components, or for simplicity and additional features use Imageresizer ( http://imageresizing.net/ )

Also see bertrand's follow up posts: http://weblogs.asp.net/bleroy/archive/2010/05/03/the-fastest-way-to-resize-images-from-asp-net-and-it-s-more-supported-ish.aspx and http://weblogs.asp.net/bleroy/archive/2011/10/22/state-of-net-image-resizing-how-does-imageresizer-do.aspx for advice on the various approaches to achieving fast web-based resizing

As a side-comment:

If your application is using HttpSession , make sure it is either disabled for this Controller or at least read-only, using:

[SessionState(SessionStateBehavior.ReadOnly)]

That way at least 2 requests can execute in parallel.

Also, if the amount of images and sizes will be limited and not too large, you might be able to simplify all this by just using OutputCache both at the client and the server setting (in memory). You'd avoid writing the images to physical storage, and resized output would get reused between users.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM