2 из 2 оценили этот материал как полезный Оценить эту тему

Объединяем RSS-каналы

Автор:
  • Петер Бернхардт (Peter Bernhardt), Компания 3Leaf Development

Продукты и технологии: Visual Basic Express Edition или Visual C# Express Edition

Статья посвящена методам расширения базового пользовательского элемента управления RSS для работы более чем с одним веб-каналом. Объединяя тематическую информацию из разных источников, можно расширить охват тем, предоставляемых на веб-узле. Пользователи веб-узла могут отбирать и компоновать информацию нужным для себя образом.


 текст программы на языке C#
 текст программы на языке Visual Basic

Основываясь на предыдущей моей публикации, в этой статье я хочу показать, как можно расширить наш базовый пользовательский элемент управления RSS для работы с несколькими веб-каналами. Объединяя тематическую информацию из разных источников, можно расширить охват тем, предоставляемых на веб-узле. Пользователи веб-узла могут отбирать и компоновать информацию нужным для себя образом.

В качестве источника интересной вспомогательной информации хотелось бы упомянуть статью Кента Шарки (Kent Sharkey) на сайте MSDN, озаглавленную "E Pluriblog Unum: Merging RSS Feeds" (EN), в которой продемонстрированы некоторые остроумные способы объединения 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-адреса:

Visual Basic

Private Sub MergeRssFeeds()
        
        
            RssData = New AggregatedRSS
        
        
            If Me.GridView1.Rows.Count > 0 Then
        
        
                For i As Integer = 0 To Me.GridView1.Rows.Count - 1
        
        
                    AddRssFeed(Me.GridView1.Rows(i).Cells(2).Text, _
        
        
                        Me.GridView1.Rows(i).Cells(3).Text)
        
        
                Next i
        
        
            End If
        
        
            Me.Repeater1.DataSource = RssData
        
        
            Me.Repeater1.DataBind()
        
        
        End Sub

Visual C#

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-потоке. Чтобы сделать пояснения более наглядными, ниже приведены несколько первых строк исходного текста:

Visual Basic

Private Sub AddRssFeed(ByVal feedTitle As String, ByVal feedUrl As String)
        
        
            Dim rssReader As XmlTextReader = Nothing
        
        
            Dim itemCount As Integer = 0
        
        
        
        
        
            Try
        
        
                Dim rssFeed As WebRequest = WebRequest.Create(feedUrl)
        
        
                rssReader = New XmlTextReader(rssFeed.GetResponse().GetResponseStream())
        
        
                While rssReader.Read
        
        
                    [see detail below]
        
        
                End While
        
        
            Finally
        
        
                If Not rssReader Is Nothing Then rssReader.Close()
        
        
            End Try
        
        
        End Sub

Visual C#

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.

Visual Basic

While rssReader.Read
        
        
            If rssReader.IsStartElement And ("item" = rssReader.LocalName) Then
        
        
                Dim itemReader As XmlReader = Nothing
        
        
                Try
        
        
                    Dim newRow As AggregatedRSS.RssItemRow = RssData.RssItem.NewRssItemRow()
        
        
                    itemReader = rssReader.ReadSubtree()
        
        
                    newRow.Feed = feedTitle
        
        
                    While itemReader.Read
        
        
                        If itemReader.IsStartElement Then
        
        
                            If ("title" = itemReader.LocalName) Then
        
        
                                newRow.Title = itemReader.ReadString
        
        
                            ElseIf ("description" = itemReader.LocalName) Then
        
        
                                Dim newDescription As String = itemReader.ReadString
        
        
                                ' Ограничиваем длину описания до 100 символов
        
        
                                If newDescription.Length > 100 Then
        
        
                                    newDescription = newDescription.Substring(0, 100) + " ..."
        
        
                                End If
        
        
                                    newRow.Description = newDescription
        
        
                                ElseIf ("link" = itemReader.LocalName) Then
        
        
                                    newRow.Link = itemReader.ReadString
        
        
                                End If
        
        
                            End If
        
        
                    End While
        
        
                    RssData.RssItem.AddRssItemRow(newRow)
        
        
                    itemCount = itemCount + 1
        
        
                Finally
        
        
                    If Not itemReader Is Nothing Then itemReader.Close()
        
        
                End Try
        
        
            End If
        
        
            ' В каждом канале читаем только первые 5 сообщений
        
        
            If itemCount >= 5 Then Exit While
        
        
        End while

Visual C#

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();
        
        
                        //Ограничиваем длину описания до 100 символов
        
        
                        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();
        
        
                }
        
        
                // В каждом канале читаем только первые 5 сообщений 
        
        
                if (itemCount >= 5) break;
        
        
            }
        
        
        }

Это — весь программный текст, необходимый для объединения информации из RSS-каналов. Как видно, самой сложной частью создания приложения была настройка объекта XmlReader и перебор списка этих объектов для извлечения необходимых данных из веб-каналов. Но после выполнения этой задачи исключительные возможности ASP.NET по привязке к данным делают создание этого приложения очень простым.

Рис. 11.

Заглядывая вперед, скажем, что следующим шагом в развитии этого проекта будет разделение компонентов диспетчера веб-каналов и показа веб-каналов в различные элементы управления и добавление настройки веб-частей ASP.NET 2.0. До следующей встречи!

Была ли вам полезна эта информация?
(2000 символов осталось)