HTTP Image Handler偶尔无法返回图像

时间:2013-08-22 09:32:05

标签: c# httphandler

我正在使用.NET HTTP处理程序(IsReusable设置为true)来返回基于指定ID的图像。传递的URL看起来像这个ReadImage.ashx?id=N。一旦句柄收到请求,它就会获取ID并在HTTP缓存中查找以前的base64编码图像,如下所示:

byte[] image;
if (context.Cache["image_" + id] != null)
{
    image = Convert.FromBase64String(context.Cache["image_" + id].ToString());
}

如果它不存在,它继续从数据库中获取文件名,从磁盘读取文件,将其编码为base64并将字节存储在image中,最后将图像缓存20分钟,如下所示: / p>

else
{
    var dbImage = m_database.Images.Single(i => i.Id.Equals(id));
    string filePath = context.Server.MapPath(string.Format("~/{base path}/{0}", dbImage.Filename));
    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        image = new byte[fs.Length];
        fs.Read(image, 0, image.Length);
        context.Cache.Add("image_" + dbImage.Id, Convert.ToBase64String(image), null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(20), CacheItemPriority.Normal, null);
    }
}

然后我终于BinaryWrite我的image缓冲区到当前上下文的输出流:

context.Response.ContentType = "image/png";
context.Response.BinaryWrite(image);
context.Response.Flush();

现在,这一切都很好 - 但并不是所有时间。我偶尔会得到一张破损的图像,但刷新图像的时间是(99%的时间)。

查看Chrome调试器中的网络流量,我可以看到我的处理程序在图像被破坏而不是text/html的情况下返回image/png。我已经尝试将我的处理程序包装在try-catch中并记录异常详细信息,但它没有做任何事情 - 它只是继续将垃圾返回到请求页面。

image handler issue

到目前为止,我尝试了一些事情:

  1. 以4096个块缓冲我的image
  2. 创建Bitmap对象并将其返回。
  3. 完全删除缓存(如果我这样做,则会稍微失败)。
  4. 尝试捕获异常并记录它们(它永远不会抛出异常)。
  5. 我错过了这里显而易见的事吗?我有点难过,有人有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我的猜测。我的问题在于以下代码:

if (context.Cache["image_" + id] != null)
{
    image = Convert.FromBase64String(context.Cache["image_" + id].ToString());
}

缓存可能在任何时间变为无效。很有可能在if语句求值为true之后,缓存项立即变为无效,最终第二次获取将变为null。最好这样做(不是100%肯定):

var base64String = context.Cache["image_" + id].ToString();
if (base64String != null) image = ...

答案 1 :(得分:0)

不是解决方案,而是更好的解决方法。

我决定为它创建一个MVC动作,而不是使用通用处理程序。这是行动,我没有一次失败,而且似乎要快得多。

[HttpGet]
public ActionResult GetImage(int id)
{
    byte[] buffer;
    if (HttpContext.Cache["image_" + id] == null)
    {
        var dbMediaItem = m_database.MediaItems.Single(i => i.Id.Equals(id));
        string path = string.Format(Server.MapPath("~/{base path}/{0}"), dbMediaItem.Filename);
        using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);
            HttpContext.Cache.Add("image_" + id, Convert.ToBase64String(buffer), null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(20), CacheItemPriority.Normal, null);
        }
    }
    else
    {
        buffer = Convert.FromBase64String(HttpContext.Cache["image_" + id].ToString());
    }
    return base.File(buffer, "image/png");
}