coding4fun:集成聚合内容

前端之家收集整理的这篇文章主要介绍了coding4fun:集成聚合内容前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

coding4fun:集成聚合内容

发布日期: 2007-01-15 | 更新日期: 2007-01-15

本文将介绍如何将基本的 RSS 用户控件扩展到处理多个内容提要。将来自各种来源的聚合内容进行组合(最简单的叫法为“聚合”)可以扩大网站所提供的信息范围,并允许以专门针对用户需要的方式进行信息关联。(本文还包含指向英文网站的链接。)

Peter Bernhardt

3Leaf Development(英文)

难易程度:容易

所需时间: 1-3 小时

费用:免费

软件:Visual Basic 或 Visual C# Express Edition(英文)

硬件:

下载:

C# 下载(英文)

VB 下载(英文)

在本文中,我将在上期文章的基础上向您介绍如何将基本的 RSS 用户控件扩展到处理多个内容提要。将来自各种来源的聚合内容进行组合(最简单的叫法为“聚合”)可以扩大网站所提供的信息范围,并允许以专门针对用户需要的方式进行信息关联。

我想提及的一个值得注意的背景信息是 Kent Sharkey 的 MSDN 文章 E Pluriblog Unum:Merging RSS Feeds(英文),此文章展示了一些用于将 RSS 提要合并为单个文件的绝佳方法。尽管此文章基于 .NET Framework 的 1.1 版本撰写而成,但您仍可以使用此文所附带的源代码来跳跃式启动您自己的项目。我没有亲自实践过,但确实借用了一些有关如何将聚合内容聚合到一个综合视图中的想法。

我首先考虑的是如何管理由各个提要组成的列表。尽管可以使用多种不同的方法来跟踪源提要的列表(例如,概要处理标记语言 (OPML) 文件),但我决定利用 sql Server 2005 Express Edition 和增强的 ASP.NET 2.0 数据绑定模型来实现基本的 RSS 提要管理器。除了 ASP.NET 2.0 在数据访问方面提供的易用性之外,我选择此方法的主要原因是,它为充分利用通过 Web 部件框架实现的个性化服务创造了条件。终究到底,此类应用程序的根本目标是使各个用户可以选择他们自己的提要列表。但让我们先稍安勿躁;本文的主旨是表明如何管理提要列表其本身。

在刚刚创建的 Visual Studio Web Developer Express 项目中,我添加了一个新的 sql 数据库。我在该数据库中创建了一个单独的表并将其命名为 Feeds。通过使用集成的表设计器,我在此表中配置了三个列:一个标识列和两个分别用于存储提要标题和位置的基于字符串的列。


接下来,将一个新的“Web 用户控件”添加到项目中。从“工具箱”将 sqlDataSource 控件拖动到“Web 用户控件”的设计表面。此控件是 ASP.NET 2.0 中增强的数据访问模型的基础控件。它实现了用户界面控件与 ADO.NET 托管提供程序(例如,我在此应用程序中使用的 sql 数据库)之间的直接连接。我从智能标记菜单选择了“配置数据源...”来启动数据源配置向导。


我按照向导中的步骤为数据库创建了一个新的连接字符串,并确保选择了将连接字符串信息保存到应用程序配置文件的选项。该向导提供了一个用于构建默认 sql SELECT 语句的页面。您可以输入自定义 sql 语句或存储过程,或者执行我的操作并使用数据库中的可用表来直接构建查询语句。


一旦选择了表,可用列就会立即显示在“列”列表中。在您选择各个列的过程中,显示页面上的 SELECT 语句文本会相应更新。向导中的下一页允许您测试查询。这一步在此例中没有多大用处,因为我未在数据库添加任何数据。

完成向导后,我返回“工具箱”并将 GridView 控件添加到“Web 用户控件”页面。随即显示 GridView 控件的智能标记菜单,然后我使用“选择数据源”下拉菜单将 DataSourceID 属性设置为 sqlDataSource 控件。


接下来,我从智能标记菜单中选择“编辑列”一项来编辑 GridView 的列。我使用编辑器将标识列 (FeedId) 设为不可见,并且更新 title 列和 url 列的标头文本,以便它们能够在网页上显示出更漂亮的外观。


我还使用“自动套用格式”编辑器(可从智能标记菜单访问)更新了 GridView 的外观。然后转到 GridView 控件的“属性”窗口。为使用户可以直接在列表内更新或删除项,我将 AutoGenerateDeleteButton 和 AutoGenerateEditButton 属性更改为 true。这样会自动改变 GridView 在设计器中的外观。如下所示,此时在网格左侧显示出“编辑”和“删除链接


ADO.NET 2.0 对象模型非常简单,其中由 sqlDataSource 控件代表其绑定的服务器控件来负责对数据源执行 CRUD 操作。在此例中,sqlDataSource 控件不仅负责执行检索数据的 SELECT 语句,还要执行 DELETE 和 UPDATE 命令。通过使用 sqlDataSource 控件的“属性”窗口,我打开了 DeleteQuery 属性的“命令和属性编辑器”并键入了执行删除所必需的 sql 语句。


请注意,我使用的参数以 @original_FeedId 的形式写出。sqlDataSource 控件还有另一个标题为 OldValuesParameterFormatString 的属性,此属性用于指定输入参数在查询中的显示外观。此属性的默认值为 original_{0},其中 {0} 为参数实际值的占位符。另请注意,我将 Parameter source 的值改为了 Control,并将 ControlID 值改为指向 GridView 控件。我按照同样的步骤在 sqlDataSource 控件的 UpdateQuery 属性添加了 UPDATE sql 语句。

很好,一切都进行得很顺利。但我发现要向数据库添加新记录,使用 GridView 并不是一种简单的方法。您可以通过多种不同方法解决此问题(包括创造性地使用 GridView 的页脚模板)。我的解决方案是使用 DetailsView 控件。与 GridView 一样,它是另一个用于数据访问的多用途工具。它使您可以浏览整组数据(一次显示一个记录)、更新或删除当前记录或添加新记录。您还可以将此控件与 GridView 联用来实现典型的主数据/明细数据表示。在该应用场景中,GridView 仅显示一组可选项,当其中某项被选中时,将以明细形式显示在 DetailsView 控件中。这些控件的灵活性使您在为网页提供最佳用户界面时有了广泛的选择空间。就我个人而言,我愿意通过 GridView 提供直接的编辑和删除,而使用 DetailsView 来添加新记录。


在 GridView 下方直接添加一个 DetailsView 控件后,我将其 DataSourceID 属性设置为 sqlDataSource 控件,并确保只有其 AutoGenerateInsertButton 属性被设置为 true。为了提升性能,我将 EnabledViewState 属性更改为 false。完成后,我在 sqlDataSource 控件的 InsertQuery 属性添加执行数据库 INSERT 所必需的 sql 文本。


InsertQuery 属性sqlDataSource 控件的其他有关查询属性在配置方面的唯一区别是,InsertQuery 的 ControlID 设置为 DetailsView 控件(而不是 GridView)。

不寻常的是,我无需编写一行代码就实现了用于管理提要列表的所有逻辑。当然,下载和合并提要又是另外一回事,但此时的确应该停下来感叹一下 ASP.NET 2.0 数据绑定体系结构的强大功能和简易性。

显示聚合的 RSS 2.0 提要,第一个要逾越的障碍就是实现一个共用数据格式。由于仅需要显示少数几个标准数据项(项、说明和链接),因此我决定使用强类型化 DataSet 来存储从各提要收集的数据。此方法的主要优点在于,我可以将所得数据轻松地绑定到用户界面控件。将新的 DataSet 添加到项目后,我在设计器中将其打开并且创建一个含有四个列的 DataTable(如下所示)。


除了三个基本的项属性之外,我还添加了一个名为 Feed 的列来存储源 RSS 提要的名称,以便我能够在网页上显示此信息。

接下来,我在 FeedManager 控件的代码文件添加两个专用方法。第一个方法 MergeRSSFeeds 从控件的 Load 事件处理程序调用。第一行代码创建了强类型化 AggregateRSS 数据集(用于保存从 RSS 提要提取的数据)的一个类级实例。该代码随后遍历代表每个已配置 RSS 提要的 GridView 控件行。在 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 提要时出现" + 
        " Web 异常。<br/>请确保您与 Internet 的连接" + 
        "有效。</p><p><em>{0}<em></p>",wx.Message);
        Literal1.Visible = true;
    }
}

在循环末尾,代码将 Repeater 控件的 DataSource 属性设置为填充好的 DataSet,然后调用 Repeater 的 DataBind 方法将数据绑定到控件。

在此应用程序中,由辅助方法 AddRSSFeed 负责执行多数繁重的任务。该代码首先使用 WebRequest 类取出 RSS 提要,再将数据加载到 XmlTextReade 中。然后,该代码设置一个 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())
        {
             [See the detail below]
        }
    }
    finally
    {
        if (itemReader != null) itemReader.Close();
    }
}

在 While 外循环中,代码查找名为“item”的元素。这表明 RSS 提要项是当前节点。在这种情况下,代码创建一个新的 RSSItemRow 来存储项数据,然后使用父 XmlReader 的 ReadSubTree 方法创建一个新的 XmlReader 对象。此读取器(名为 itemReader)将保存当前的 RSS 项数据。代码调用内部 XmlReader 的 Read 方法来查找所需的每个数据项。找到后,代码将数据值存储在 RSSItemRow 的相应单元格中。在 While 内循环末尾,代码调用 DataTable 的强类型化 AddRSSItemRow 方法将该行添加到 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 卓越的数据绑定功能就会使构建此应用程序变得易如反掌。


如果考虑以后,此项目进展的下一步就是将提要管理器和提要显示组件分离为不同的控件,以及添加个性化服务 ASP.NET 2.0 Web 部件框架。那就等到下次再讨论吧

猜你在找的设计模式相关文章