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.