Отображение двоичных данных в веб-элементах управления данными (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
. В следующем руководстве мы посмотрим, как это сделать, но пока нам нужно вручную указать значения для этого столбца.
В этом руководстве вы найдете в ~/Brochures
папке семь pdf-файлов буклетов, по одному для каждой категории, кроме морепродуктов. Я намеренно опущен добавление брошюры "Морепродукты", чтобы проиллюстрировать, как обрабатывать сценарии, когда не все записи имеют связанные двоичные данные. Чтобы обновить таблицу Categories
с этими значениями, щелкните правой кнопкой мыши Categories
узел в Обозреватель сервера и выберите пункт Показать данные таблицы. Затем введите виртуальные пути к файлам буклетов для каждой категории, в которых есть брошюра, как показано на рисунке 1. Так как для категории Морепродукты нет брошюры, оставьте BrochurePath
значение столбца как NULL
.
Рис. 1. Введите значения столбца Categories
BrochurePath
таблицы вручную (щелкните для просмотра полноразмерного изображения)
Шаг 2. Предоставление ссылки для скачивания брошюр в GridView
С помощью значений BrochurePath
, предоставленных Categories
для таблицы, мы вновь готовы создать Элемент GridView, который перечисляет каждую категорию, а также ссылку для скачивания брошюры категории. На шаге 4 мы расширим этот gridView, чтобы отобразить изображение категории.
Начните с перетаскивания GridView с панели элементов на Designer DisplayOrDownloadData.aspx
страницы в папкеBinaryData
. Задайте для gridView значение ID
Categories
и с помощью смарт-тега GridView выберите привязку к новому источнику данных. В частности, привяжите его к объекту ObjectDataSource с именем CategoriesDataSource
, который извлекает данные с помощью CategoriesBLL
метода объекта GetCategories()
.
Рис. 2. Создание объекта ObjectDataSource с именем CategoriesDataSource
(щелкните, чтобы просмотреть полноразмерное изображение)
Рис. 3. Настройка ObjectDataSource для использования CategoriesBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 4. Получение списка категорий с помощью GetCategories()
метода (щелкните для просмотра полноразмерного изображения)
После завершения работы мастера настройки источника данных Visual Studio автоматически добавит BoundField в Categories
GridView для CategoryID
, CategoryName
, Description
, NumberOfProducts
и BrochurePath
DataColumn
. NumberOfProducts
Удалите BoundField, так как GetCategories()
запрос метода не получает эти сведения. Также удалите CategoryID
BoundField и переименуйте CategoryName
свойства и BrochurePath
BoundFields HeaderText
в Category и Буклет соответственно. После внесения этих изменений декларативная разметка 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. Морепродукты, которые имеют NULL
значение для , BrochurePath
отображает пустую ячейку.
Рис. 5. Имя, описание и BrochurePath
значение каждой категории отображаются в списке (щелкните, чтобы просмотреть полноразмерное изображение)
Вместо отображения текста столбца BrochurePath
мы хотим создать ссылку на брошюру. Для этого удалите BrochurePath
BoundField и замените его на HyperLinkField. Задайте для нового свойства HyperLinkField HeaderText
значение Буклет, для его Text
свойства — значение Просмотреть брошюру, а для свойства DataNavigateUrlFields
— значение BrochurePath
.
Рис. 6. Добавление HyperLinkField для BrochurePath
При этом будет добавлен столбец ссылок на GridView, как показано на рисунке 7. Если щелкнуть ссылку Просмотреть брошюру, pdf-файл отобразится непосредственно в браузере или пользователю будет предложено скачать файл в зависимости от того, установлено ли средство чтения PDF и параметры браузера.
Рис. 7. Брошюру категории можно просмотреть, щелкнув ссылку "Просмотреть брошюру" (щелкните для просмотра полноразмерного изображения)
Рис. 8. Отображается PDF-файл брошюры категории (щелкните для просмотра полноразмерного изображения)
Скрытие текста брошюры для категорий без брошюры
Как показано на рисунке BrochurePath
7, HyperLinkField отображает значение свойства Text
("Просмотреть брошюру") для всех записей, независимо от того, имеется ли значение, отличноеNULL
от значения для BrochurePath
. Конечно, если BrochurePath
имеет значение NULL
, ссылка отображается только в виде текста, как в случае с категорией Морепродукты (см. рис. 7). Вместо того чтобы отображать текст Просмотреть брошюру, было бы неплохо, чтобы в этих категориях без BrochurePath
значения отображались альтернативные тексты, например Нет брошюры.
Чтобы обеспечить такое поведение, необходимо использовать TemplateField, содержимое которого создается путем вызова метода страницы, который выдает соответствующие выходные данные на BrochurePath
основе значения. Мы впервые изучили этот метод форматирования еще в руководстве Использование templateFields в элементе управления GridView .
Преобразуйте HyperLinkField в TemplateField, выбрав BrochurePath
HyperLinkField и щелкнув ссылку Преобразовать это поле в TemplateField в диалоговом окне Изменение столбцов.
Рис. 9. Преобразование HyperLinkField в TemplateField
При этом будет создан шаблон TemplateField с элементом управления ItemTemplate
, содержащим веб-элемент управления HyperLink, свойство которого 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
. При этом не устанавливайте флажок Выбрать страницу master. Эта страница ожидает значение в строках 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
метода класса s 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[], это может быть вызвано двумя способами. Во-первых, столбец Categories
таблицы Picture
допускает 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
оператор метода SELECT
s GetCategoryWithBinaryDataByCategoryID
вернулся к списку столбцов запроса main, что может произойти при использовании нерегламентированных инструкций SQL и повторном запуске мастера для запроса main TableAdapter. Убедитесь, что GetCategoryWithBinaryDataByCategoryID
оператор метода SELECT
по-прежнему Picture
содержит столбец.
Примечание
При каждом посещении DisplayCategoryPicture.aspx
выполняется доступ к базе данных и возвращаются данные рисунка указанной категории. Однако если изображение категории не изменилось с момента последнего просмотра пользователем, это напрасно. К счастью, HTTP позволяет использовать условные методы GET. При использовании условного GET клиент, выполняющий HTTP-запрос, отправляет заголовокIf-Modified-Since
HTTP, который предоставляет дату и время последнего получения клиентом этого ресурса с веб-сервера. Если содержимое не изменилось с указанной даты, веб-сервер может ответить кодом состояния "Не изменено" (304) и отказаться от отправки обратного содержимого запрошенного ресурса. Короче говоря, этот метод избавляет веб-сервер от необходимости отправлять обратно содержимое для ресурса, если оно не было изменено с момента последнего доступа клиента к нему.
Однако для реализации этого поведения необходимо добавить PictureLastModified
столбец в Categories
таблицу для записи времени Picture
последнего обновления столбца, а также код для проверка заголовкаIf-Modified-Since
. Дополнительные сведения о заголовке If-Modified-Since
и условном рабочем процессе GET см. в разделах Http Conditional GET for RSS Hackers и A Deeper Look at Performing HTTP Requests in a ASP.NET Page.
Шаг 4. Отображение изображений категорий в GridView
Теперь, когда у нас есть веб-страница для отображения изображения определенной категории, мы можем отобразить ее с помощью элемента управления Image Web или ЭЛЕМЕНТА HTML <img>
, указывающего на DisplayCategoryPicture.aspx?CategoryID=categoryID
. Изображения, URL-адрес которых определяется данными базы данных, можно отобразить в GridView или DetailsView с помощью ImageField. ImageField содержит DataImageUrlField
свойства и DataImageUrlFormatString
, которые работают так же, как свойства и DataNavigateUrlFormatString
HyperLinkFieldDataNavigateUrlFields
.
Давайте добавим Categories
GridView в DisplayOrDownloadData.aspx
, добавив ImageField для отображения рисунка каждой категории. Просто добавьте ImageField и задайте для его DataImageUrlField
свойств CategoryID
и DataImageUrlFormatString
значения и DisplayCategoryPicture.aspx?CategoryID={0}
соответственно. При этом будет создан столбец GridView, который отображает <img>
элемент, атрибут которого src
ссылается на DisplayCategoryPicture.aspx?CategoryID={0}
, где {0} заменяется значением строки 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.
Теперь, когда мы рассмотрели, как отображать двоичные данные, мы готовы изучить, как выполнять вставку, обновление и удаление в базе данных с помощью двоичных данных. В следующем руководстве мы рассмотрим, как связать отправленный файл с соответствующей записью базы данных. В этом руководстве мы посмотрим, как обновить существующие двоичные данные, а также как удалить двоичные данные при удалении связанной с ними записи.
Счастливого программирования!
Об авторе
Скотт Митчелл( Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Он может быть доступен в mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.
Особая благодарность
Эта серия учебников была рассмотрена многими полезными рецензентами. Ведущим рецензентом этого руководства были Тетера Мерфи и Дэйв Гарднер. Хотите просмотреть предстоящие статьи MSDN? Если да, опустите мне строку на mitchell@4GuysFromRolla.com.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по