在ASP.NET C#中将byte[]数据流转换为图像

5

我在SQL Server数据库中存储了一个图片,并与用户数据一起检索出来。

现在我直接在页面上拥有了byte[]。我该如何将它放入WebControls.Image中?我不想调用HttpHandler并再次调用数据库。

显然,这只是将它输出到整个页面。

            Context.Response.BinaryWrite(user.Picture.ToArray());

你能不能不将图像数据存储为文件? - AnthonyWJones
这是第一条路线,但将图像存储在数据库中是首选解决方案。(超出我的能力范围)因此,我必须充分利用这种情况。 - markoo
感谢大家的帮助。快速而深入的回答。 - markoo
嵌入base64图像是最后的选择。即使有额外的数据库流量,使用单独的请求也可以使页面更具响应性。有一个库可以使它变得非常容易。SqlReader类作为VirtualPathProvider函数,比HttpHandler提供更好的性能。您可以将其与DiskCache插件结合使用,以获得极佳的性能。 - Lilith River
5个回答

4
如果是小图片,您可以将其输出为base64编码数据到图像标记中。在这里查看类似情况
但在99.9%的情况下,您会创建一个HttpHandler来返回图像。我认为这是最简单和最快的方式。

你应该注意,并非所有浏览器都能读取存储在行内的大量数据。请务必在支持的所有浏览器中充分测试页面。 - Rune Grimstad
谢谢您的提示。目前我已在IE,FF和Chrome中进行了测试,即使图片大小达到400 KB也可以正常工作。 - markoo
好的,刚刚发现这在IE pre8中不起作用,因为我在我的开发机上有IE8,但我们公司内部的用户还没有!啊! - markoo
哦不!我认为它应该适用于较小的图像,但这可能无法解决您的问题 :-( - Rune Grimstad
一个VirtualPathProvider甚至更好,因为你不必在HttpHeader中重新实现所有的HTTP支持。我编写了一个SqlReader提供程序,它就是这样做的,而且非常容易设置。 - Lilith River
显示剩余3条评论

1

将字节数组包装在MemoryStream对象中,并将其放置在ASP.NET的缓存中。

MemoryStream ms = new MemoryStream(user.Picture.ToArray());
Guid imageGuid = new Guid();
HttpRuntime.Cache.Add(imageGuid.ToString(), ms, null,
    DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

然后使用处理程序(.ashx)从缓存中获取它并将其发送给客户端。
string imageGuid = context.Request.QueryString[image];
MemoryStream ms = (MemoryStream)HttpRuntime.Cache[imageGuid];
// configure context.Response with appropriate content type and cache settings

// ** Edit **
// It seems I need to be more explicit with regard to the above comment:-
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetLastModified(DateTime.UtcNow);
context.Response.Cache.SetExpires(DateTime.UtcNow.AddHours(2);
context.Response.Cache.SetMaxAge(TimeSpan.FromHours(2));
context.Response.Cache.SetValidUntilExpires(true);

ms.WriteTo(context.Response.OutputStream);

现在你可以从缓存中删除MemoryStream。
HttpRuntime.Cache.Remove(imageGuid);

这个在 Web 农场中无法扩展(除非你有某种分布式缓存)。 - LukeH
永远不要这样做。你牺牲了HTTP的所有好处(如If-Modified-Since、缓存等)和可扩展性,却没有任何好处。 - Anton Gogolev
@Luke:相反,充分利用 Web Farm 正是使用缓存的好处所在。在 WLB 环境中,会话通常与农场中的服务器相关联。拥有 Web Farm 的整个目的是减轻数据库层的压力,而缓存是该解决方案的非常重要的一部分。 - AnthonyWJones
@Anthony:内置的ASP.NET缓存,如你示例代码所使用的,不是分布式的:每台Web服务器都有自己的缓存。如果您的图像请求命中了另一台服务器,则图像数据将无法在其缓存中找到。(显然,如果您的Web农场使用粘性会话,则不适用此规则,但这也有其自身的可扩展性问题。) - LukeH
Memcached缓存图片效果不佳 - 它们很少被更新,并且在每次重启后都会丢失。而且你需要大量的RAM。磁盘缓存更好,可以提供内核模式速度。 - Lilith River
显示剩余3条评论

0
创建一个单独的页面,例如:image.aspx,在该页面上创建图像,并在其他页面上使用它。
<img src="image.aspx?id=number" >

number是数据库中图像的ID


不要使用ASPX来输出图像,而应该使用ASHX。 - AnthonyWJones
@Anthony:OP说他们不想使用ashx,虽然我同意这是正确的做法。(而且创建一个aspx也不比创建一个ashx容易!) - LukeH
@Anthony:我不知道它们的区别。这只是扩展名,不是吗?甚至可以使用路由来命名为even number.jpg。 - x2.
4
MS将ASPX文件描述为ASP.NET“表单”,这是有原因的。它带来了与完整表单生命周期相关的相当大的开销(初始化控件、加载控件、处理回发、预呈现、呈现、卸载、释放等)。如果你只需要调整响应对象的属性并将一块数据输出,那么你就不需要这些操作。在这种情况下,.ashx是更简单和更清晰的解决方案。 - AnthonyWJones
@Luke:OP想要避免使用处理程序的原因是为了避免再次从数据库中读取图片,我并不反对使用处理程序,只是避免不必要地重复执行一个重要操作。 - AnthonyWJones
我想防止再次调用数据库。我已经从第一次调用中获取了数据。 - markoo

0
你需要一个 IHttpHander,它将把图像字节和适当的 Content-Type 写入响应流中。请参见 this, thisthis

你在问题中错过了重点。假设在一个正在执行的ASPX页面中,你有一个从数据库获取的图像数据的字节数组,如何在输出中获取<img>以显示该图像而不重新查询数据库? - AnthonyWJones
@Anthony:当然,关键在于他不需要在页面本身中提取图像数据。他不需要重新查询数据库-他需要在适当的位置/时间(即在单独的ashx处理程序中)查询一次即可。 - LukeH
@Luke:也许是这样,但我们并不知道对吧?从问题中我们只知道他有一个已经加载了图片对象的对象,原因未知。或许更好的方法是避免这种情况,最好将图片放在文件系统中。我更喜欢回答手头上的问题,特别是因为其他一些SO用户可能会发现他们无法避免这种情况。 - AnthonyWJones
这也是我在谷歌上找到的唯一解决方案,但对我没有用,因为我已经从数据库中获取了数据,不想浪费另一个调用。 - markoo

0

我非常确定您不能在页面本身中执行此操作。

如果您不想创建HTTP处理程序来输出图像,则替代方法是创建一个单独的aspx页面。将img标记的src设置为指向该页面,通过查询字符串传递某种ID,以便可以从数据库中提取图像数据。

话虽如此,设置aspx页面来执行此操作并不比设置ashx更快或更容易。我建议按照正确的方式进行操作,并创建HTTP处理程序。


我已经从数据库中获取了数据。我想要避免再次调用。 - markoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接