0

我正在开发一个 .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应有的情况下返回。我尝试将我的处理程序包装在 a 中try-catch并记录异常详细信息,但它没有做任何事情 - 它只是继续将垃圾返回到请求页面。

图像处理程序问题

到目前为止,我已经尝试了几件事:

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

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

4

2 回答 2

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 = ...
于 2013-08-22T09:42:11.907 回答
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");
}
于 2013-08-22T11:36:19.740 回答