ASp.Net Mvc 1.0 Dynamic Images Returned from Controller taking 154 seconds+ to display in IE8, firefox and all other browsers fast and easy
I have a curious problem with IE, IIS 6.0 dynamic PNG files and I am baffled as to how to fix..
Snippet from Helper (this returns the URL to the view for requesting the images from my Controller.
string url = LinkBuilder.BuildUrlFromExpression(helper.ViewContext.RequestContext, helper.RouteCollection, c => c.FixHeight(ir.Filename, ir.AltText, "FFFFFF")); url = url.Replace("&", "&"); sb.Append(string.Format("<removed id=\"TheImage\" src=\"{0}\" alt=\"\" />", url)+Environment.NewLine);
This produces a piece of html as follows:- img id="TheImage" src="/ImgText/FixHeight?sFile=Images%2FUser%2FJulianGuppy%2FMediums%2Fconservatory.jpg&backgroundColour=FFFFFF" alt="" /
brackets missing because i cant post an image... even though I dont want to post an image I jsut want to post the markup... sigh
Snippet from Controller ImgTextController
/// <summary>
/// This function fixes the height of the image
/// </summary>
/// <param name="sFile"></param>
/// <param name="alternateText"></param>
/// <param name="backgroundColour"></param>
/// <returns></returns>
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FixHeight(string sFile, string alternateText, string backgroundColour)
{
#region File
if (string.IsNullOrEmpty(sFile))
{
return new ImgTextResult();
}
// MVC specific change to prepend the new directory
if (sFile.IndexOf("Content") == -1)
{
sFile = "~/Content/" + sFile;
}
// open the file
System.Drawing.Image img;
try
{
img = System.Drawing.Image.FromFile(Server.MapPath(sFile));
}
catch
{
img = null;
}
// did we fail?
if (img == null)
{
return new ImgTextResult();
}
#endregion File
#region Width
// Sort out the width from the image passed to me
Int32 nWidth = img.Width;
#endregion Width
#region Height
Int32 nHeight = img.Height;
#endregion Height
// What is the ideal height given a width of 2100 this should be 1400.
var nIdealHeight = (int)(nWidth / 1.40920096852);
// So is the actual height of the image already greater than the ideal height?
Int32 nSplit;
if (nIdealHeight < nHeight)
{
// Yes, do nothing, well i need to return the iamge...
nSplit = 0;
}
else
{
// rob wants to not show the white at the top or bottom, so if we were to crop the image how would be do it
// 1. Calculate what the width should be If we dont adjust the heigt
var newIdealWidth = (int)(nHeight * 1.40920096852);
// 2. This newIdealWidth should be smaller than the existing width... so work out the split on that
Int32 newSplit = (nWidth - newIdealWidth) / 2;
// 3. Now recrop the image using 0-nHeight as the height (i.e. full height)
// but crop the sides so that its the correct aspect ration
var newRect = new Rectangle(newSplit, 0, newIdealWidth, nHeight);
img = CropImage(img, newRect);
nHeight = img.Height;
nWidth = img.Width;
nSplit = 0;
}
// No, so I want to place this image on a larger canvas and we do this by Creating a new image to be the size that we want
System.Drawing.Image canvas = new Bitmap(nWidth, nIdealHeight, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(canvas);
#region Color
// Whilst we can set the background colour we shall default to white
if (string.IsNullOrEmpty(backgroundColour))
{
backgroundColour = "FFFFFF";
}
Color bc = ColorTranslator.FromHtml("#" + backgroundColour);
#endregion Color
// Filling the background (which gives us our broder)
Brush backgroundBrush = new SolidBrush(bc);
g.FillRectangle(backgroundBrush, -1, -1, nWidth + 1, nIdealHeight + 1);
// draw the image at the position
var rect = new Rectangle(0, nSplit, nWidth, nHeight);
g.DrawImage(img, rect);
return new ImgTextResult { Image = canvas, ImageFormat = ImageFormat.Png };
}
My ImgTextResult is a class that returns an Action result for me but embedding the image from a memory stream into the response.outputstream.
snippet from my ImageResults
/// <summary>
/// Execute the result
/// </summary>
/// <param name="context"></param>
public override void ExecuteResult(ControllerContext context)
{
// output
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = "image/png";
try
{
var memStream = new MemoryStream();
Image.Save(memStream, ImageFormat.Png);
context.HttpContext.Response.BinaryWrite(memStream.ToArray());
context.HttpContext.Response.Flush();
开发者_Go百科 context.HttpContext.Response.Close();
memStream.Dispose();
Image.Dispose();
}
catch (Exception ex)
{
string a = ex.Message;
}
}
Now all of this works locally and lovely, and indeed all of this works on my production server
BUT Only for Firefox, Safari, Chrome (and other browsers) IE has a fit and decides that it either wont display the image or it does display the image after approx 154seconds of waiting.....
I have made sure my HTML is XHTML compliant, I have made sure I am getting no Routing errors or crashes in my event log on the server....
Now obviously I have been a muppet and have done something wrong... but what I cant fathom is why in development all works fine, and in production all non IE browsers also work fine, but IE 8 using IIS 6.0 production server is having some kind of problem in returning this PNG and I dont have an error to trace... so what I am looking for is guidance as to how I can debug this problem.
Looks like it might be time to install Fiddler or HttpWatch and find out what is going on.
Well, what I wanted to do was to convert my images (jpg, bmp, etc... and return them as png) - however. Although all other browsers would accept the encoding and display them fine, IE decided to hide the png image (after partially displaying it) because it thought it wasn't a PNG image. (Even though it was) So I gave up with the conversion methods and just returned the image in its original format. ---
if anybody comes up with a way of reliably converting any image format into png so that I can return it dynamically from a memory stream, then please do let me know....
So I am closing this for now as IE has won this battle -
I wish IE would just sod off and die. I hate IE so much. Seriously it just sucks the sweat of a dead mans balls.
Never call Response.End()
At least, that's what the maintainer for the HttpResponse documentation says.
Response.End() ends the http connection, often orphaning data in the server's buffer or somewhere in the stream. It's better to let IIS end the connection (or reuse it) instead, since many clients don't have a perfect network stack.
IE has a terrible network stack (as anyone who has used IETab for FF can witness, IE is almost fast when placed on top of the FF network pipe). The other browsers handle the quickly closed connection much better, and so probably aren't responding badly to the closed connection.
On a different topic, it looks like you are re-inventing the wheel. It's not an easy wheel to build properly, either.
Based on the code I see, it looks like you are leaking the GDI bitmap 'img', and additional leaks would occur if anything unexpected happened during the request. Note that .NET does not garbage collection GDI handles properly, and it's one of the biggest causes of server crashes - make sure you get that fixed, my friend :)
精彩评论