Динамический рендеринг asp: изображение из BLOB-записи в ASP.NET
Чего я хочу добиться, так это. Я хочу дать пользователю возможность загружать файл изображения, сохранять изображение в BLOB в SQL Server, а затем использовать это изображение в качестве логотипа на других страницах сайта.
Я сделал это с помощью
Response.Clear();
Response.ContentType = "image/pjpeg";
Response.BinaryWrite(imageConents);
Response.End();
но для этого я использую пользовательский элемент управления в том месте, где я хочу показать изображение. Я хочу сделать это, если это возможно, используя элемент управления asp: Image или даже чистый старый HTML-элемент управления изображением. Это возможно?
6 ответов
Добавьте "универсальный обработчик" в ваш веб-проект, назовите его как-то так: Image.ashx. Реализуйте это так:
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
using(Image image = GetImage(context.Request.QueryString["ID"]))
{
context.Response.ContentType = "image/jpeg";
image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
public bool IsReusable
{
get
{
return true;
}
}
}
Теперь просто реализуйте метод GetImage, чтобы загрузить изображение с заданным идентификатором, и вы можете использовать
<asp:Image runat="server" ImageUrl="~/Image.ashx?ID=myImageId" />
показать это. Возможно, вы захотите подумать и о реализации некоторой формы кэширования в обработчике. И помните, что если вы хотите изменить формат изображения на PNG, вам нужно использовать промежуточный MemoryStream (поскольку PNG требуют, чтобы был сохранен доступный для поиска поток).
Вы можете BASE64 кодировать содержимое изображения непосредственно в атрибут SRC, однако, я считаю, что только Firefox будет анализировать это обратно в изображение.
Обычно я создаю очень легкий HTTPHandler для обслуживания изображений:
using System;
using System.Web;
namespace Example
{
public class GetImage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.QueryString("id") != null)
{
Blob = GetBlobFromDataBase(id);
context.Response.Clear();
context.Response.ContentType = "image/pjpeg";
context.Response.BinaryWrite(Blob);
context.Response.End();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
Вы можете ссылаться на это непосредственно в вашем теге img:
<img src="GetImage.ashx?id=111"/>
Или вы можете даже создать серверный элемент управления, который сделает это за вас:
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Example.WebControl
{
[ToolboxData("<{0}:DatabaseImage runat=server></{0}:DatabaseImage>")]
public class DatabaseImage : Control
{
public int DatabaseId
{
get
{
if (ViewState["DatabaseId" + this.ID] == null)
return 0;
else
return ViewState["DataBaseId"];
}
set
{
ViewState["DatabaseId" + this.ID] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write("<img src='getImage.ashx?id=" + this.DatabaseId + "'/>");
base.RenderContents(output);
}
}
}
Это может быть использовано как
<cc:DatabaseImage id="db1" DatabaseId="123" runat="server/>
И, конечно, вы можете установить databaseId в коде, если это необходимо.
Вы не хотите обслуживать большие двоичные объекты из базы данных без реализации кэширования на стороне клиента.
Вам потребуется обработать следующие заголовки для поддержки кэширования на стороне клиента:
- ETag
- Истекает
- Последнее изменение
- If-Match
- If-None-Match
- If-Modified-Since
- Если-Unmodified-С
- Если-нет Modified-Since
Для обработчика http, который делает это, проверьте: http://code.google.com/p/talifun-web/wiki/StaticFileHandler
Это хороший помощник для обслуживания контента. Это должно быть легко передать поток базы данных к нему. Он также выполняет кэширование на стороне сервера, что должно помочь снизить нагрузку на базу данных.
Если вы когда-нибудь решите обслуживать потоковое содержимое из базы данных, файлов PDF или больших файлов, обработчик также поддерживает 206 частичных запросов.
Он также поддерживает сжатие gzip и deflate.
Эти типы файлов выиграют от дальнейшего сжатия:
- css, js, htm, html, swf, xml, xslt, txt
- док, xls, ppt
Существует несколько типов файлов, которые не выиграют от дальнейшего сжатия:
- pdf (вызывает проблемы с некоторыми версиями в IE, и обычно он хорошо сжат)
- PNG, JPG, JPEG, GIF, ICO
- WAV, MP3, M4A, AAC (WAV часто сжимается)
- 3gp, 3g2, asf, avi, dv, flv, mov, mp4, mpg, mpeg, wmv
- почтовый индекс, rar, 7z, arj
Используя ASP.Net с MVC, это довольно просто. Вы кодируете контроллер с помощью такого метода:
public FileContentResult Image(int id)
{
//Get data from database. The Image BLOB is return like byte[]
SomeLogic ItemsDB= new SomeLogic("[ImageId]=" + id.ToString());
FileContentResult MyImage = null;
if (ItemsDB.Count > 0)
{
MyImage= new FileContentResult(ItemsDB.Image, "image/jpg");
}
return MyImage;
}
В вашем веб-представлении ASP.NET или, в этом примере, в веб-форме ASP.NET вы можете заполнить элемент управления изображения URL-адресом вашего метода следующим образом:
this.imgExample.ImageUrl = "~/Items/Image/" + MyItem.Id.ToString();
this.imgExample.Height = new Unit(120);
this.imgExample.Width = new Unit(120);
Вуаля. Не надо было хлопот HttpModules.
Добавьте код в обработчик, чтобы вернуть байты изображения с соответствующим MIME-типом. Затем вы можете просто добавить URL к вашему обработчику, как будто это изображение. Например:
<img src="myhandler.ashx?imageid=5">
Есть смысл?
На самом деле мы только что выпустили несколько классов, которые помогают именно с такими вещами:
http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16449
В частности, проверьте образец DatabaseImage.