Отображение двоичных данных в веб-элементах управления данными (C#)
В этом руководстве мы рассмотрим параметры представления двоичных данных на веб-странице, включая отображение файла изображения и подготовку ссылки "Скачать" для PDF-файла.
Введение
В предыдущем руководстве мы изучили два метода связывания двоичных данных с базовой моделью данных приложения и использовали элемент управления FileUpload для отправки файлов из браузера в файловую систему веб-сервера. Мы еще не узнали, как связать отправленные двоичные данные с моделью данных. То есть после отправки и сохранения файла в файловой системе путь к файлу должен храниться в соответствующей записи базы данных. Если данные хранятся непосредственно в базе данных, то переданные двоичные данные не должны быть сохранены в файловой системе, но их необходимо внедрить в базу данных.
Прежде чем рассматривать связывание данных с моделью данных, давайте сначала рассмотрим, как предоставить двоичные данные конечному пользователю. Отображение текстовых данных достаточно просто, но как должны быть представлены двоичные данные? Это зависит, конечно, от типа двоичных данных. Для изображений, скорее всего, мы хотим отобразить изображение; для PDF-файлов, документов Microsoft Word, ZIP-файлов и других типов двоичных данных, предоставляя ссылку для скачивания, вероятно, более подходит.
В этом руководстве мы рассмотрим, как представить двоичные данные вместе с связанными текстовыми данными с помощью веб-элементов управления данными, таких как GridView и DetailsView. В следующем руководстве мы переключим внимание на связывание отправленного файла с базой данных.
Шаг 1. ПредоставлениеBrochurePath
значений
Столбец Picture
в Categories
таблице уже содержит двоичные данные для различных образов категорий. В частности, Picture
столбец для каждой записи содержит двоичное содержимое зернистого, низкого качества, 16-цветового растрового изображения. Каждое изображение категории имеет ширину 172 пикселей и 120 пикселей высотой и потребляет примерно 11 КБ. Кроме того, двоичное содержимое в Picture
столбце содержит 78-байтовый заголовок OLE , который необходимо удалить перед отображением изображения. Эти сведения о заголовке присутствуют, так как база данных Northwind имеет свои корни в Microsoft Access. В Access двоичные данные хранятся с помощью типа данных OLE Object, который применяется в этом заголовке. Теперь мы посмотрим, как отрезать заголовки от этих низкокачественного изображения, чтобы отобразить рисунок. В следующем руководстве мы создадим интерфейс для обновления столбца Picture
категории и заменим эти растровые изображения, использующие заголовки OLE с эквивалентными изображениями JPG без ненужных заголовков OLE.
В предыдущем руководстве мы узнали, как использовать элемент управления FileUpload. Таким образом, вы можете идти вперед и добавить файлы брошюры в файловую систему веб-сервера. Однако это не обновляет BrochurePath
столбец в Categories
таблице. В следующем руководстве мы посмотрим, как это сделать, но теперь нам нужно вручную указать значения для этого столбца.
В этом руководстве вы найдете семь PDF-файлов брошюр в папке ~/Brochures
, по одному для каждой категории, кроме морепродуктов. Я намеренно опущен добавление брошюры "Морепродукты", чтобы иллюстрировать, как обрабатывать сценарии, где не все записи имеют связанные двоичные данные. Чтобы обновить Categories
таблицу с этими значениями, щелкните правой кнопкой мыши Categories
узел из обозревателя серверов и выберите "Показать данные таблицы". Затем введите виртуальные пути к файлам брошюр для каждой категории, которая содержит брошюру, как показано на рисунке 1. Так как нет брошюры для категории "Морепродукты", оставьте значение столбца BrochurePath
как NULL
.
Рис. 1. Введите значения столбца Categories
BrochurePath
таблицы вручную (щелкните, чтобы просмотреть изображение полного размера)
Шаг 2. Предоставление ссылки на скачивание для брошюр в GridView
BrochurePath
При использовании значений, предоставленных для Categories
таблицы, мы готовы создать GridView, который перечисляет каждую категорию вместе со ссылкой для скачивания брошюры категории. На шаге 4 мы расширим этот GridView, чтобы также отобразить изображение категории.
Начните с перетаскивания GridView из панели элементов в конструктор DisplayOrDownloadData.aspx
страницы в папке BinaryData
. Задайте для GridView смарт-тег GridView и с помощью смарт-тега GridView ID
Categories
, чтобы привязать его к новому источнику данных. В частности, привязать его к объекту ObjectDataSource с именем CategoriesDataSource
, который извлекает данные с помощью CategoriesBLL
метода объекта GetCategories()
.
Рис. 2. Создание объекта ObjectDataSource С именем (CategoriesDataSource
щелкните, чтобы просмотреть изображение полного размера)
Рис. 3. Настройка ObjectDataSource для использования CategoriesBLL
класса (щелкните, чтобы просмотреть изображение полного размера)
Рис. 4. Получение списка категорий с помощью GetCategories()
метода (щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера настройки источника данных Visual Studio автоматически добавит BoundField в Categories
GridView для CategoryID
, CategoryName
и BrochurePath
Description
NumberOfProducts
DataColumn
s. Запустите и удалите NumberOfProducts
BoundField, так как GetCategories()
запрос метода не извлекает эти сведения. Также удалите BoundField и переименуйте CategoryID
BrochurePath
CategoryName
свойства BoundFields HeaderText
в категории и брошюры соответственно. После внесения этих изменений декларативная разметка GridView и ObjectDataSource должны выглядеть следующим образом:
<asp:GridView ID="Categories" runat="server"
AutoGenerateColumns="False" DataKeyNames="CategoryID"
DataSourceID="CategoriesDataSource" EnableViewState="False">
<Columns>
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
<asp:BoundField DataField="BrochurePath" HeaderText="Brochure"
SortExpression="BrochurePath" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Просмотрите эту страницу через браузер (см. рисунок 5). В списке перечислены все восемь категорий. Семь категорий со BrochurePath
значениями имеют BrochurePath
значение, отображаемое в соответствующем BoundField. Морепродукты, которые имеют значение для негоBrochurePath
, отображает пустую NULL
ячейку.
Рис. 5. Имя каждой категории, описание и BrochurePath
значение перечислены (щелкните, чтобы просмотреть изображение полного размера)
Вместо отображения текста столбца BrochurePath
мы хотим создать ссылку на брошюру. Для этого удалите BrochurePath
BoundField и замените его гиперлинкфилдом. Присвойте новому свойству HyperLinkField значение "Брошюра" HeaderText
, свойству " Text
Просмотреть брошюру" и свойству DataNavigateUrlFields
BrochurePath
.
Рис. 6. Добавление HyperLinkField для BrochurePath
Это добавит столбец ссылок на GridView, как показано на рисунке 7. Щелкнув ссылку "Просмотреть брошюру", вы увидите PDF-файл непосредственно в браузере или предложите пользователю скачать файл в зависимости от того, установлен ли модуль чтения PDF и параметры браузера.
Рис. 7. Брошюра категории можно просмотреть, щелкнув ссылку "Просмотреть брошюру" (щелкните, чтобы просмотреть изображение полного размера)
Рис. 8. Отображается PDF-файл брошюры категории (щелкните, чтобы просмотреть изображение полного размера)
Скрытие текста брошюры представления для категорий без брошюры
Как показано на рисунке 7, HyperLinkField отображает значение свойства Text
(просмотреть брошюру) для всех записей независимо от того, BrochurePath
существуетNULL
ли значение, отличное от BrochurePath
значения. Конечно, если BrochurePath
это NULL
так, ссылка отображается только в виде текста, как и в случае с категорией "Морепродукты" (см. рис. 7). Вместо отображения брошюры представления текста может быть приятно иметь эти категории без BrochurePath
значения, отображая альтернативный текст, например нет брошюры.
Чтобы обеспечить это поведение, необходимо использовать TemplateField, содержимое которого создается с помощью вызова метода страницы, который выдает соответствующие выходные данные на BrochurePath
основе значения. Сначала мы изучили этот метод форматирования в руководстве по использованию TemplateFields в руководстве по элементу управления GridView.
Преобразуйте HyperLinkField в templateField, выбрав BrochurePath
HyperLinkField и нажав кнопку "Преобразовать это поле" в ссылку TemplateField в диалоговом окне "Изменить столбцы".
Рис. 9. Преобразование HyperLinkField в templateField
Будет создан шаблонField с ItemTemplate
элементом управления HyperLink Web, свойство которого NavigateUrl
привязано к значению BrochurePath
. Замените эту разметку вызовом метода GenerateBrochureLink
, передавая значение BrochurePath
:
<asp:TemplateField HeaderText="Brochure">
<ItemTemplate>
<%# GenerateBrochureLink(Eval("BrochurePath")) %>
</ItemTemplate>
</asp:TemplateField>
Затем создайте protected
метод в классе кодовой части страницы ASP.NET, который GenerateBrochureLink
возвращает string
и принимает object
входной параметр.
protected string GenerateBrochureLink(object BrochurePath)
{
if (Convert.IsDBNull(BrochurePath))
return "No Brochure Available";
else
return string.Format(@"<a href="{0}">View Brochure</a>",
ResolveUrl(BrochurePath.ToString()));
}
Этот метод определяет, является ли переданное object
значение базой данных NULL
и, если да, возвращает сообщение, указывающее, что категория не имеет брошюры. В противном случае, если имеется BrochurePath
значение, оно отображается в гиперссылке. Обратите внимание, что если BrochurePath
значение присутствует, оно передается в ResolveUrl(url)
метод. Этот метод разрешает переданный URL-адрес, заменив ~
символ соответствующим виртуальным путем. Например, если приложение является корневым /Tutorial55
, ResolveUrl("~/Brochures/Meats.pdf")
возвращается /Tutorial55/Brochures/Meat.pdf
.
На рисунке 10 показана страница после применения этих изменений. Обратите внимание, что поле категории "Морепродукты" BrochurePath
теперь отображает текст "Нет брошюры доступны".
Рис. 10. Текст недоступен для этих категорий без брошюры (щелкните, чтобы просмотреть изображение полного размера)
Шаг 3. Добавление веб-страницы для отображения рисунка категории
Когда пользователь посещает страницу ASP.NET, он получает HTML-код страницы ASP.NET. Полученный HTML-код является просто текстом и не содержит двоичных данных. Любые дополнительные двоичные данные, такие как изображения, звуковые файлы, приложения Macromedia Flash, внедренные Медиаплеер Windows видео и т. д., существуют в виде отдельных ресурсов на веб-сервере. HTML содержит ссылки на эти файлы, но не включает фактическое содержимое файлов.
Например, в HTML <img>
элемент используется для ссылки на рисунок с src
атрибутом, указывающим на файл изображения следующим образом:
<img src="MyPicture.jpg" ... />
Когда браузер получает этот HTML-код, он отправляет другой запрос на веб-сервер, чтобы получить двоичное содержимое файла изображения, который затем отображается в браузере. Та же концепция применяется к любым двоичным данным. На шаге 2 брошюра не была отправлена в браузер в рамках разметки HTML страницы. Скорее, отрисованный HTML-код предоставил гиперссылки, которые при щелчке привели к тому, что браузер запрашивает PDF-документ напрямую.
Чтобы отобразить или разрешить пользователям загружать двоичные данные, находящиеся в базе данных, необходимо создать отдельную веб-страницу, которая возвращает данные. Для нашего приложения существует только одно двоичное поле данных, хранящееся непосредственно в базе данных, изображение категории. Поэтому нам нужна страница, которая при вызове возвращает данные изображения для определенной категории.
Добавьте новую страницу ASP.NET в папку BinaryData
с именем DisplayCategoryPicture.aspx
. При этом оставьте флажок "Выбор главной страницы" снят. Эта страница ожидает CategoryID
значение в запросе и возвращает двоичные данные столбца этой категории Picture
. Так как эта страница возвращает двоичные данные и ничего другого, она не нуждается в разметке в разделе HTML. Поэтому щелкните вкладку "Источник" в левом нижнем углу и удалите все разметки страницы, кроме директивы <%@ Page %>
. То есть декларативная DisplayCategoryPicture.aspx
разметка должна состоять из одной строки:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="DisplayCategoryPicture.aspx.cs"
Inherits="BinaryData_DisplayCategoryPicture" %>
Если атрибут отображается MasterPageFile
в директиве <%@ Page %>
, удалите его.
В классе кода страницы добавьте следующий код в Page_Load
обработчик событий:
protected void Page_Load(object sender, EventArgs e)
{
int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
// Get information about the specified category
CategoriesBLL categoryAPI = new CategoriesBLL();
Northwind.CategoriesDataTable categories =
categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
Northwind.CategoriesRow category = categories[0];
// Output HTTP headers providing information about the binary data
Response.ContentType = "image/bmp";
// Output the binary data
// But first we need to strip out the OLE header
const int OleHeaderLength = 78;
int strippedImageLength = category.Picture.Length - OleHeaderLength;
byte[] strippedImageData = new byte[strippedImageLength];
Array.Copy(category.Picture, OleHeaderLength,
strippedImageData, 0, strippedImageLength);
Response.BinaryWrite(strippedImageData);
}
Этот код начинается с чтения в значении CategoryID
запроса в переменную с именем categoryID
. Затем данные рисунка извлекаются с помощью вызова CategoriesBLL
метода класса GetCategoryWithBinaryDataByCategoryID(categoryID)
. Эти данные возвращаются клиенту с помощью Response.BinaryWrite(data)
метода, но перед этим Picture
вызовом необходимо удалить заголовок OLE значения столбца. Это достигается путем создания массива byte
с именем strippedImageData
, который будет содержать ровно 78 символов меньше, чем то, что находится в столбце Picture
. Метод Array.Copy
используется для копирования данных начиная с category.Picture
позиции 78 сверхуstrippedImageData
.
Свойство Response.ContentType
указывает тип MIME возвращаемого содержимого, чтобы браузер знал, как его отрисовать. Categories
Так как столбец таблицы Picture
представляет собой растровое изображение, то здесь используется тип MIME растрового изображения (image/bmp). Если опустить тип MIME, большинство браузеров по-прежнему будут отображать изображение правильно, так как они могут выводить тип на основе содержимого двоичных данных файла изображения. Однако рекомендуется включить тип MIME, если это возможно. Полный список типов носителей MIME см. на веб-сайте Центра назначения номеров Интернета.
С помощью этой страницы можно просмотреть изображение определенной категории, перейдя на страницу DisplayCategoryPicture.aspx?CategoryID=categoryID
. На рисунке 11 показан рисунок категории напитков, с которого можно просмотреть DisplayCategoryPicture.aspx?CategoryID=1
.
Рис. 11. Изображение категории напитков отображается (щелкните, чтобы просмотреть изображение полного размера)
Если при посещении DisplayCategoryPicture.aspx?CategoryID=categoryID
вы получите исключение, которое считывает сообщение "Не удается привести объект типа System.DBNull" для типа System.Byte[], это может быть вызвано двумя вещами. Во-первыхPicture
, Categories
столбец таблицы разрешает NULL
значения. Однако на DisplayCategoryPicture.aspx
странице предполагается, что присутствует значение, отличноеNULL
от значения. Свойство Picture
объекта CategoriesDataTable
невозможно получить напрямую NULL
, если оно имеет значение. Если вы хотите разрешить NULL
значения для столбца Picture
, необходимо включить следующее условие:
if (category.IsPictureNull())
{
// Display some "No Image Available" picture
Response.Redirect("~/Images/NoPictureAvailable.gif");
}
else
{
// Send back the binary contents of the Picture column
// ... Set ContentType property and write out ...
// ... data via Response.BinaryWrite ...
}
В приведенном выше коде предполагается, что в Images
папке, которая будет отображаться для этих категорий без рисунка, существует некоторый файл NoPictureAvailable.gif
изображения.
Это исключение также может быть вызвано, если CategoriesTableAdapter
оператор метода s GetCategoryWithBinaryDataByCategoryID
SELECT
вернулся к списку столбцов основного запроса, что может произойти, если вы используете нерегламентированные инструкции SQL, и вы повторно запустите мастер для основного запроса TableAdapter. Убедитесь, что GetCategoryWithBinaryDataByCategoryID
оператор метода SELECT
по-прежнему Picture
содержит столбец.
Примечание.
DisplayCategoryPicture.aspx
При каждом посещении база данных обращается и возвращаются данные рисунка указанной категории. Если рисунок категории не изменился, так как пользователь в последний раз просматривал его, однако это не требует усилий. К счастью, HTTP позволяет условным GET. При использовании условного GET клиент, выполняющий HTTP-запрос, отправляет If-Modified-Since
по заголовку HTTP, который предоставляет дату и время последнего получения этого ресурса клиентом с веб-сервера. Если содержимое не изменилось с указанной даты, веб-сервер может ответить с кодом состояния "Не изменено" (304) и заготовить отправку содержимого запрошенного ресурса. Короче говоря, этот метод позволяет веб-серверу от необходимости отправлять обратное содержимое для ресурса, если он не был изменен с момента последнего доступа к нему клиента.
Однако для реализации этого поведения требуется добавить PictureLastModified
столбец в Categories
таблицу для отслеживания последнего Picture
обновления столбца, а также кода для проверки заголовка If-Modified-Since
. Дополнительные сведения о заголовке и условном рабочем процессе GET см. в If-Modified-Since
статье HTTP Условный GET для хакеров RSS и более подробный обзор выполнения HTTP-запросов на странице ASP.NET.
Шаг 4. Отображение изображений категорий в GridView
Теперь, когда у нас есть веб-страница для отображения изображения определенной категории, мы можем отобразить его с помощью элемента управления "Веб-изображение" или элемента HTML <img>
, указывающего на DisplayCategoryPicture.aspx?CategoryID=categoryID
него. Изображения, URL-адрес которых определяется данными базы данных, можно отобразить в GridView или DetailsView с помощью ImageField. ImageField содержит DataImageUrlField
и свойства, которые работают так же, как и свойства HyperLinkField DataNavigateUrlFields
DataNavigateUrlFormatString
.DataImageUrlFormatString
Давайте добавим Categories
GridView DisplayOrDownloadData.aspx
, добавив imageField, чтобы отобразить рисунок каждой категории. Просто добавьте ImageField и задайте его DataImageUrlField
и DataImageUrlFormatString
свойства CategoryID
DisplayCategoryPicture.aspx?CategoryID={0}
соответственно. При этом будет создан столбец GridView, который отображает элемент, ссылки DisplayCategoryPicture.aspx?CategoryID={0}
{0} на атрибуты <img>
которого src
заменяются значением CategoryID
строки GridView.
Рис. 12. Добавление ImageField в GridView
После добавления ImageField декларативный синтаксис GridView должен выглядеть следующим образом:
<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False"
DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
<asp:TemplateField HeaderText="Brochure">
<ItemTemplate>
<%# GenerateBrochureLink(Eval("BrochurePath")) %>
</ItemTemplate>
</asp:TemplateField>
<asp:ImageField DataImageUrlField="CategoryID"
DataImageUrlFormatString="DisplayCategoryPicture.aspx?CategoryID={0}">
</asp:ImageField>
</Columns>
</asp:GridView>
Просмотрите эту страницу через браузер. Обратите внимание, что каждая запись теперь содержит рисунок для категории.
Рис. 13. Рисунок категории отображается для каждой строки (щелкните, чтобы просмотреть изображение полного размера)
Итоги
В этом руководстве мы рассмотрели, как представить двоичные данные. Способ представления данных зависит от типа данных. Для PDF-файлов брошюр мы предложили пользователю ссылку "Просмотреть брошюру", которая при щелчке взяла пользователя непосредственно в PDF-файл. Для рисунка категории сначала мы создали страницу для получения и возврата двоичных данных из базы данных, а затем использовали эту страницу для отображения каждого рисунка категории в GridView.
Теперь, когда мы рассмотрели, как отобразить двоичные данные, мы готовы изучить, как выполнять вставку, обновление и удаление базы данных с двоичными данными. В следующем руководстве мы рассмотрим, как связать загруженный файл с соответствующей записью базы данных. В руководстве после этого мы посмотрим, как обновить существующие двоичные данные, а также как удалить двоичные данные при удалении связанной записи.
Счастливое программирование!
Об авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.
Особое спасибо
Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты для этого руководства были Тереса Мерфи и Дэйв Гарднер. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.