patterncsharpMinor
Why is loading images taking so long?
Viewed 0 times
whylongloadingimagestaking
Problem
When Page_Load is executed I assign the ImageUrl which is a
Which looks like this:
The handler call is a static method from
This method simply loads image binaries from the database and converts them to Images:
So basically this is all that happens when loading images. It is possible that
But now I am experiencing some delays when loading an image:
Now i wo
IHTTPHandler:imgView.ImageUrl = "ImageHandler.ashx" + "?rezeptId=" + rezeptId.ToString() +"&imageId=0";Which looks like this:
public class ImageHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
int rezeptId = Int32.Parse(context.Request.QueryString["rezeptId"]);
int imageId = Int32.Parse(context.Request.QueryString["imageId"]);
List images = DBManager.GetRezeptImages(rezeptId);
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(Helper.ImageToByteArray(images[imageId]));
}
public bool IsReusable {
get {
return false;
}
}
}The handler call is a static method from
DBManager, a custom static class which provides LINQ-To-SQL queries. The method is called GetRezeptImages():public static List GetRezeptImages(int rezeptId)
{
using (CookBookDataContext ctx = new CookBookDataContext(Resources.ResourceFile.DBConnection))
{
IEnumerable bilder = from b in ctx.RezeptBilders where b.FKRezept == rezeptId select b;
List imageList = new List();
foreach (RezeptBilder b in bilder)
{
imageList.Add(Helper.ByteArrayToImage(b.Bild.ToArray()));
}
return imageList;
}
}This method simply loads image binaries from the database and converts them to Images:
public static Image ByteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}So basically this is all that happens when loading images. It is possible that
GetRezeptImages() will return a List with more than one image but it is always only one that is loaded to image control.But now I am experiencing some delays when loading an image:
Now i wo
Solution
So, let us see what you are doing.
You query your database for
Then you are converting the
As you don't use methods of the
and to be called
But this shouldn't fix your issue. Taking 28 seconds for accessing 1.3 MB comes down to about 48 Kbyte/s which is quit slow.
To check where the most time is used, you need to measure the time it takes to execute the call to
Smaller images will for sure speed the whole thing up and therefor makes the user of the website happy.
General
What will happen if a user of the site is changing the image url inside the address bar like
Your
Also you will get an exception, if the requested
Style
You should be consistent with your coding style. It is a matter of taste where to place the opening braces
You query your database for
IEnumerable and iterate over the enumeration where you are converting the items to Image and add it to a List.Then you are converting the
Image back to a Byte[] to write it into the response stream. Byte[] -> Image -> Byte[] isn't really necessary. As you don't use methods of the
List but rather of the interface IList we will return an IList as it is always better to code against an interface instead of an implementation. public static IList GetRezeptImages(int rezeptId)
{
using (CookBookDataContext ctx = new CookBookDataContext(Resources.ResourceFile.DBConnection))
{
IEnumerable bilder = from b in ctx.RezeptBilders where b.FKRezept == rezeptId select b;
IList imageList = new List();
foreach (RezeptBilder b in bilder)
{
imageList.Add(b.Bild.ToArray());
}
return imageList;
}
}and to be called
public void ProcessRequest (HttpContext context)
{
int rezeptId = Int32.Parse(context.Request.QueryString["rezeptId"]);
int imageId = Int32.Parse(context.Request.QueryString["imageId"]);
IList images = DBManager.GetRezeptImages(rezeptId);
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(images[imageId]);
}But this shouldn't fix your issue. Taking 28 seconds for accessing 1.3 MB comes down to about 48 Kbyte/s which is quit slow.
To check where the most time is used, you need to measure the time it takes to execute the call to
GetRezeptImages(). Smaller images will for sure speed the whole thing up and therefor makes the user of the website happy.
General
What will happen if a user of the site is changing the image url inside the address bar like
ImageHandler.ashx?rezeptId=testForTryParse&imageId=0 ? Your
ProcessRequest() method would throw an exception. You should carefully validate the input. This can be done in this case by using Int32.TryParse() instead of Int32.Parse(). Also you will get an exception, if the requested
imageId is greater than the count of the IList. public class ImageHandler : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
int rezeptId = 0;
int imageId = 0;
if( Int32.TryParse(context.Request.QueryString["rezeptId"], out rezeptId) &&
Int32.TryParse(context.Request.QueryString["imageId"], out imageId))
{
IList images = DBManager.GetRezeptImages(rezeptId);
if (images.Count > imageId)
{
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(images[imageId]);
return;
}
}
// a proper defined error response here
}
public bool IsReusable
{
get
{
return false;
}
}
}Style
You should be consistent with your coding style. It is a matter of taste where to place the opening braces
{. Most do it on a new line, some place it on the same line. But you should stick to it.Code Snippets
public static IList<Byte[]> GetRezeptImages(int rezeptId)
{
using (CookBookDataContext ctx = new CookBookDataContext(Resources.ResourceFile.DBConnection))
{
IEnumerable<RezeptBilder> bilder = from b in ctx.RezeptBilders where b.FKRezept == rezeptId select b;
IList<Byte[]> imageList = new List<Byte[]>();
foreach (RezeptBilder b in bilder)
{
imageList.Add(b.Bild.ToArray());
}
return imageList;
}
}public void ProcessRequest (HttpContext context)
{
int rezeptId = Int32.Parse(context.Request.QueryString["rezeptId"]);
int imageId = Int32.Parse(context.Request.QueryString["imageId"]);
IList<Byte[]> images = DBManager.GetRezeptImages(rezeptId);
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(images[imageId]);
}public class ImageHandler : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
int rezeptId = 0;
int imageId = 0;
if( Int32.TryParse(context.Request.QueryString["rezeptId"], out rezeptId) &&
Int32.TryParse(context.Request.QueryString["imageId"], out imageId))
{
IList<Byte[]> images = DBManager.GetRezeptImages(rezeptId);
if (images.Count > imageId)
{
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(images[imageId]);
return;
}
}
// a proper defined error response here
}
public bool IsReusable
{
get
{
return false;
}
}
}Context
StackExchange Code Review Q#70496, answer score: 3
Revisions (0)
No revisions yet.