Объединяем RSS-каналы
Автор: Петер Бернхардт (Peter Bernhardt), Компания 3Leaf Development
Взято
отсюда
Статья посвящена методам расширения базового пользовательского элемента управления RSS для работы более чем с одним веб-каналом. Объединяя тематическую информацию из разных источников, можно расширить охват тем, предоставляемых на веб-узле. Пользователи веб-узла могут отбирать и компоновать информацию нужным для себя образом.
Основываясь на предыдущей моей публикации, в этой статье я хочу показать, как можно расширить наш базовый пользовательский элемент управления RSS для работы с несколькими веб-каналами. Объединяя тематическую информацию из разных источников, можно расширить охват тем, предоставляемых на веб-узле. Пользователи веб-узла могут отбирать и компоновать информацию нужным для себя образом.
В качестве источника интересной вспомогательной информации хотелось бы упомянуть статью Кента Шарки (Kent Sharkey) на сайте MSDN, озаглавленную
"E Pluriblog Unum: Merging RSS Feeds", в которой продемонстрированы некоторые остроумные способы объединения RSS-каналов в один файл. Поскольку статья основана на версии 1.1 среды .NET Framework, приложенный к ней исходный текст можно использовать в качестве основы для создания собственных проектов. Я не делал этого сам, но использовал некоторые идеи по агрегированию тематического содержимого в сводное представление.
Первая рассмотренная задача — управление списком отдельных веб-каналов. Хотя для отслеживания списка исходных веб-каналов можно использовать целый ряд различных способов, например, файл на языке
Outline Processor Markup Language (OPML), для реализации базового диспетчера RSS-каналов я решил использовать возможности сервера SQL Server 2005 Express Edition и возможности работы с данными среды ASP.NET 2.0. Основной причиной для выбора такого метода явилось наличие в ASP.NET 2.0 готовой среды для личной настройки – так называемых веб-частей. В конечном счете основная задача приложения такого типа — предоставление индивидуальным пользователям возможности выбора собственного списка веб-каналов. Но не будем забегать вперед: в этой статье мы рассмотрим управление самим списком веб-каналов.
Создав новый проект в среде Visual Studio Web Developer Express, добавим к нему новую базу данных SQL. Создадим в базе данных единственную таблицу с именем feeds (веб-каналы). При помощи встроенного конструктора таблиц создадим в таблице три столбца: столбец идентификаторов и два столбца для строковых значений, в которых будут храниться название и адрес веб-канала.
Рисунок 1.
Теперь добавим к проекту новый пользовательский веб-элемент управления. С панели инструментов перетащим элемент управления SqlDataSource в поле конструктора пользовательского веб-элемента управления. Элемент SqlDataSource является краеугольным камнем усовершенствованной модели доступа к данным в среде ASP.NET 2.0. Он обеспечивает непосредственное подключение элементов управления пользовательского интерфейса к управляемому поставщику ADO.NET (в данном случае, к базе данных SQL). В меню смарт-тега выберем «Configure Data Source...» (Настроить источник данных...), после чего запустится соответствующий мастер настройки.
Рисунок 2.
Воспользуемся мастером для создания новой строки подключения к базе данных, удостоверившись в том, что включено сохранение строки подключения в файле конфигурации приложения. Мастер предоставляет страницу для создания инструкции SELECT языка SQL, используемой по умолчанию. Здесь можно задать собственную инструкцию языка SQL или хранимую процедуру; мы же воспользуемся имеющейся в базе данных таблицей для непосредственного создания инструкции запроса.
Рисунок 3.
После выбора таблицы доступные столбцы появляются в списке «Columns». При выборе тех или иных столбцов текст инструкции SELECT соответствующим образом обновляется. На следующей странице мастера можно протестировать запрос. В данном случае это не слишком эффективно, поскольку в базе нет данных.
После завершения работы мастера вернемся к панели инструментов и добавим на страницу пользовательского веб-элемента управления элемент GridView. Немедленно появится меню смарт-тега элемента управления GridView. Воспользуемся раскрывающимся меню «Choose Data Source», и для свойства DataSourceID укажем элемент управления SqlDataSource.
Рисунок 4.
Затем в меню смарт-тега выберем пункт «Edit Columns...» (Изменить столбцы), чтобы изменить столбцы элемента управления GridView. При помощи редактора сделаем столбец идентификатора (feedId) невидимым и поменяем заголовки в столбцах title и url, чтобы они выглядели более наглядно при показе на веб-странице.
Рисунок 5.
Также обновим представление элемента управления GridView при помощи редактора автоформата (доступного в меню смарт-тега). После этого перейдем в окно «Properties» (Свойства) для элемента управления GridView. Чтобы пользователи могли обновлять или удалять элементы непосредственно в списке, изменим значения свойств AutoGenerateDeleteButton и AutoGenerateEditButton на true. При этом автоматически изменяется представление элемента GridView в конструкторе. Как показано ниже, теперь с левой стороны от сетки появились ссылки «Edit» (Изменить) и «Delete» (Удалить).
Рисунок 6.
Объектная модель среды ADO.NET 2.0 очень проста: элемент управления SqlDataSource обеспечивает выполнение операций создания, чтения, изменения и удаления (CRUD) в отношении источника данных от имени связанных с ним серверных элементов управления. В нашем случае элемент управления SqlDataSource обеспечивает выполнение не только инструкции SELECT для извлечения данных, но и инструкций DELETE и UPDATE. В окне «Properties» для элемента управления SqlDataSource для свойства DeleteQuery откроем «Command and Property Editor» (Редактор команд и свойств) и введем инструкцию SQL для удаления данных.
Рисунок 7.
Заметьте, что использованный параметр записывается в виде @original_feedId. Элемент управления SqlDataSource имеет также другое свойство, OldValuesParameterFormatString, которое указывает, каким образом входной параметр должен отображаться в запросе. По умолчанию это свойство имеет значение original_{0}, где {0} — прототип фактического значения параметра. Также заметьте, что значение свойства Parameter source изменено на Control, а значение свойства ControlID указывает на элемент управления GridView. Выполнив те же действия, добавим в свойство UpdateQuery элемента управления SqlDataSource инструкцию языка SQL UPDATE.
Все это правильно и должно работать. Однако мы видим, что элемент управления GridView не предоставляет простого способа для добавления записей в базу данных. Для решения этой проблемы имеется ряд различных способов (включая творческий подход к использованию шаблона нижнего колонтитула GridView). Мы же воспользуемся элементом управления DetailsView, который является еще одним гибким способом работы с данными. Он позволяет перемещаться в пределах набора данных, показывая записи по одной, изменять или удалять текущую запись или добавлять новую запись. Этот элемент управления может использоваться в сочетании с GridView, в результате получится классическое представление данных список и подробности. В GridViewпоказывается список доступных для выбора элементов, а подробное представление выбранных элементов выводится в DetailsView. Гибкость этих элементов управления дает большие возможности по созданию удобного пользовательского интерфейса на веб-страницах. В нашем примере представляется удобным непосредственное редактирование и удаление при помощи элемента управления GridView и использование элемента управления DetailsView для добавления записей.
Рисунок 8.
Я расположил элемент управления DetailsView непосредственно под GridView. В его свойстве DataSourceID указываем элемент управления SqlDataSource и проверяем, что значение true указано только для свойства AutoGenerateInsertButton. Для повышения производительности изменим значение свойства EnabledViewState на false. После этого добавим требуемый текст инструкции INSERT в свойство InsertQuery элемента управления SqlDataSource.
Рисунок 9.
Единственное различие между настройкой свойства InsertQuery и других свойств элемента управления SqlDataSource, связанных с запросами, заключается в том, что в качестве значения ControlID для свойства InsertQuery был указан элемент управления DetailsView (а не элемент управления GridView).
Следует отметить, что вся логика управления списком веб-каналов была реализована без написания хотя бы одной строчки текста программы. Разумеется, загрузка и объединение веб-каналов представляет собой отдельную задачу, но определенно стоит приостановиться на этом этапе, чтобы оценить мощь и простоту того, как реализована привязка к данным в среде ASP.NET 2.0.
При реализации совместного показа RSS-каналов версии 2.0, первое препятствие заключается в выборе общего формата для работы с их данными. Поскольку нам требуется показ лишь нескольких стандартных элементов информации (элементы, описания и ссылки), воспользуемся для хранения данных, полученных из каждого веб-канала, строго типизированным элементом управления DataSet. Основное преимущество такого подхода состоит в том, что можно легко привязать полученные данные к элементу управления пользовательского интерфейса. После добавления к проекту нового элемента управления DataSet откроем его в конструкторе и создадим единственный элемент DataTable с четырьмя столбцами (см. ниже).
Рисунок 10.
В дополнение к трем базовым атрибутам элемента, добавим столбец с названием Feed (веб-канал), в котором будем хранить название исходного RSS-канала с целью показа этой информации на веб-странице.
После этого добавим два закрытых метода в текст элемента управления FeedManager. Первый метод, MergeRssFeeds, вызывается из обработчика события Load элемента управления. В первой строке создается экземпляр уровня класса строго типизированного набора данных AggregateRSS. Он используется для хранения данных, полученных от RSS-каналов. После этого выполняется перебор строк элемента управления GridView, каждая из которых представляет собой RSS-канал. В цикле For выполняется вызов второго метода – AddRssFeed – с указанием в качестве параметров названия RSS-канала и его URL-адреса:
private void MergeRssFeeds()
{
RssData = new AggregatedRSS();
try
{
if (this.GridView1.Rows.Count > 0)
{
for (int i = 0; i < this.GridView1.Rows.Count; i++)
{
AddRssFeed(this.GridView1.Rows[i].Cells[2].Text,
this.GridView1.Rows[i].Cells[3].Text);
}
}
this.Repeater1.DataSource = RssData;
this.Repeater1.DataBind();
}
catch (WebException wx)
{
Literal1.Text = String.Format(
"<h3>Ошибка</h3><p>При объединении RSS-потоков возникла исключительная " +
" ситуация.<br/>Убедитесь, что есть связь с " +
"Интернетом.</p><p><em>{0}<em></p>", wx.Message);
Literal1.Visible = true;
}
}
В конце цикла в качестве свойства DataSource элемента управления Repeater указывается заполненный элемент DataSet, после чего вызывается метод DataBind элемента Repeater для привязки данных к элементу управления.
Вспомогательный метод AddRssFeed выполняет основную часть тяжелой работы в этом приложении. Сначала выполняется получение RSS-канала при помощи класса WebRequest и загрузка данных в объект XmlTextReader. После этого выполняется цикл While для перебора данных в XML-потоке. Чтобы сделать пояснения более наглядными, ниже приведены несколько первых строк исходного текста:
private void AddRssFeed(string feedTitle, string feedUrl)
{
XmlTextReader rssReader = null;
int itemCount = 0;
try
{
WebRequest rssFeed = WebRequest.Create(feedUrl);
rssReader = new xmlTextReader(rssFeed.GetResponse().GetResponseStream());
while (rssReader.Read())
{
}
}
finally
{
if (itemReader != null) itemReader.Close();
}
}
Во внешнем цикле While выполняется поиск элементов «item» в RSS-потоке. Нахождение такого элемента означает, что текущим XML-узлом является элемент данных RSS-канала. В таком случае создается новый объект RssItemRow для хранения данных из найденного элемента. Затем при помощи метода ReadSubTree родительского объекта XmlReader создается новый объект типа XmlReader под названием ItemReader. В этом объекте хранятся данные текущего элемента RSS. Для нахождения всех интересующих элементов данных вызывается метод Read дочернего объекта XmlReader. В случае результативного поиска значение данных сохраняется в соответствующей ячейке элемента RssItemRow. В конце выполнения внутреннего цикла While вызывается строго типизированный метод AddRssItemRow объекта DataTable и строки добавляются к элементу DataSet.
while (rssReader.Read())
{
if ((rssReader.IsStartElement()) && ("item" == rssReader.LocalName))
{
XmlReader itemReader = null;
try
{
AggregatedRSS.RssItemRow newRow = RssData.RssItem.NewRssItemRow();
itemReader = rssReader.ReadSubtree();
newRow.Feed = feedTitle;
while (itemReader.Read())
{
if (itemReader.IsStartElement())
{
if ("title" == itemReader.LocalName)
newRow.Title = itemReader.ReadString();
else if ("description" == itemReader.LocalName)
{
string newDescription = itemReader.ReadString();
if (newDescription.Length > 100)
newDescription = newDescription.Substring(0, 100) +
" ...";
newRow.Description = newDescription;
}
else if ("link" == itemReader.LocalName)
newRow.Link = itemReader.ReadString();
}
}
RssData.RssItem.AddRssItemRow(newRow);
itemCount++;
}
finally
{
if (itemReader != null)
itemReader.Close();
}
if (itemCount >= 5)
break;
}
}
Это — весь программный текст, необходимый для объединения информации из RSS-каналов. Как видно, самой сложной частью создания приложения была настройка объекта XmlReader и перебор списка этих объектов для извлечения необходимых данных из веб-каналов. Но после выполнения этой задачи исключительные возможности ASP.NET по привязке к данным делают создание этого приложения очень простым.
Рисунок 11.
Заглядывая вперед, скажем, что следующим шагом в развитии этого проекта будет разделение компонентов диспетчера веб-каналов и показа веб-каналов в различные элементы управления и добавление настройки веб-частей ASP.NET 2.0. До следующей встречи!