【问题标题】:HTTP Image Handler occasionally failing to return an imageHTTP 图像处理程序偶尔无法返回图像
【发布时间】:2013-08-22 19:36:19
【问题描述】:

我正在开发一个 .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 分钟:

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 中并记录异常详细信息,但它没有做任何事情 - 它只是继续将垃圾返回到请求页面。

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

  1. 以 4096 个块缓冲我的 image
  2. 创建一个Bitmap 对象并返回它。
  3. 完全删除缓存(如果我这样做,它会更频繁地失败)。
  4. 尝试捕获异常并记录它们(它从不抛出异常)。

我在这里错过了明显的东西吗?我有点难过,有人有什么建议吗?

【问题讨论】:

    标签: c# httphandler


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 不幸的是,如果我完全删除缓存,这个问题仍然存在(虽然稍微更糟),但感谢您的提醒。
    【解决方案2】:

    与其说是解决方案,不如说是更好的解决方法。

    我决定为它创建一个 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");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 2017-01-28
      相关资源
      最近更新 更多