Agrégation de contenu syndiqué

Paru le 15 janvier 2007

Cet article montre comment étendre le contrôle utilisateur de RSS de manière à gérer plus d'un type de contenu. La combinaison de contenu provenant de diverses sources ou agrégation de contenu élargit la gamme d'informations disponibles sur le site Web et permet de transmettre des informations aux utilisateurs d'une manière extrêmement pertinente.

Peter Bernhardt 3Leaf Development
Difficulté : Facile
Temps nécessaire : 1 à 3 heures
Coût : Libre

Téléchargez : Édition Visual Basic ou Visual C# Express

Dans cet article, je vous propose de vous montrer comment étendre le contrôle utilisateur de RSS de manière à gérer plus d'un type de contenu. La combinaison de contenu provenant de diverses sources ou agrégation de contenu, élargit la gamme d'informations disponibles sur le site Web et permet de transmettre des informations aux utilisateurs d'une manière extrêmement pertinente.

Dans ce contexte, je voudrais mentionner un article MDSN intéressant de Kent Sharkey, Pluriblog Unum : Fusion de flux RSS, qui démontre quelques techniques habiles visant à fusionner des flux RSS dans un seul fichier. L'article est basé sur la version 1,1 .NET Framework, mais vous pouvez utiliser le code source qui l'accompagne pour démarrer vos propres projets. Pour ma part, j'ai emprunté certaines idées sur la manière d'agréger du contenu syndiqué et de le réunir dans un seul affichage.

La première chose que j'ai considérée était comment gérer une liste de flux individuels. Il est possible d'utiliser différentes techniques pour gérer une liste de flux source tels qu'un fichier OPML (Outline Processor Markup Language), mais j'ai décidé d'utiliser SQL Server 2005 Express Edition et le modèle de liaison de données amélioré ASP.NET 2.0 pour implémenter un gestionnaire de flux RSS de base. Outre la facilité d'accès aux données proposée par ASP.NET 2.0, la raison pour laquelle j'ai choisi cette méthode est qu'elle me permet de tirer profit des services de personnalisation offerts par l'infrastructure WebPart. Après tout, l'objectif ultime de ce type d'application est de permettre aux utilisateurs individuels de choisir leur propre liste de flux. Mon objectif dans cet article est de vous montrer comment gérer la liste de flux elle-même.

Dans un nouveau projet Visual Studio Web Developer Express, j'ai ajouté une nouvelle base de données SQL. J'ai créé un tableau dans la base de données et je l'ai appelé feeds(flux). À l'aide du concepteur de tableau intégré, j'ai créé trois colonnes dans le tableau : une colonne d'identité et deux colonnes de type chaîne pour enregistrer le titre et l'emplacement du flux.

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Ensuite, j'ai ajouté un nouveau contrôle utilisateur Web au projet. De la boîte à outils, j'ai fait glisser un contrôle SqlDataSourcecontrol sur la surface de conception du contrôle utilisateur Web. Ce contrôle est la pierre angulaire du modèle d'accès aux données amélioré dans ASP.NET 2.0. Il fournit une connexion directe entre les contrôles d'interface utilisateur et un fournisseur géré par ADO.NET (tel que la base de données SQL que j'utilise dans cette application). Du menu des balises actives, j'ai sélectionné « Configure Data Source... » ( Configurer la source de données) pour lancer l'assistant de configuration des sources de données.

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Dans l'assistant, j'ai suivi les étapes servant à créer une nouvelle chaîne de connexion pour la base de données, tout en veillant à sélectionner l'option permettant d'enregistrer les informations de chaîne de connexion dans le fichier de configuration d'application. L'assistant fournit une page servant à générer l'instruction SQL SELECT par défaut. Vous pouvez entrer une instruction SQL ou procédure stockée personnalisée ou faire comme moi et utiliser le tableau disponible dans la base de données pour générer l'instruction directement.

Bb736724.rssagg_3(fr-fr,MSDN.10).gif

Une fois vous avez sélectionné un tableau, les colonnes disponibles apparaissent dans la liste des colonnes. Lorsque vous sélectionnez des colonnes individuelles, le texte de l'instruction SELECT affiché sur la page est mis à jour. La page suivante de l'assistant vous permet de tester la requête. Dans mon cas, elle ne m'a pas été utile vu que je n'avais pas de données dans la base de données.

Après l'assistant, je suis retourné à la Boîte à outils et ai ajouté un contrôle GridViewà la page de contrôle utilisateur Web. Le menu des balises actives du contrôle GridView est apparu tout de suite et j'ai utilisé le menu déroulant « Choose Data Source »(Choisir la source de données) pour régler la propriété DataSourceID sur le contrôle SqlDataSource.

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Ensuite, j'ai sélectionné l'option « Edit Columns » (Modifier les colonnes)du menu des balises actives pour modifier les colonnes de GridView. J'ai utilisé l'éditeur pour rendre la colonne d'identité (feedId) invisible et j'ai mis à jour le texte d'en-tête des colonnes des titreset des urlde sorte qu'elles soient affichées clairement sur la page Web.

Bb736724.rssagg_5(fr-fr,MSDN.10).gif

J'ai également mis à jour l'apparence du GridViewà l'aide de l'éditeur Auto Format (accessible du menu des balises actives). Je suis ensuite passé à la fenêtre des propriétés du contrôle GridView. Pour permettre aux utilisateurs de mettre à jour ou supprimer un élément directement dans la liste, j'ai réglé AutoGenerateDeleteButton et AutoGenerateEditButtonsur true(vrai). Cette opération a changé automatiquement l'apparence du GridViewdans le concepteur. Comme indiqué ci-dessous, les liens Edit (Modifier) et Delete (Supprimer) des liens sont maintenant apparus sur le côté gauche de la grille.

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Le modèle objet ADO.NET 2.0 est très simple, le contrôle SqlDataSourceétant chargé d'exécuter des opérations CRUD par rapport à une source de données au profit de ses contrôles serveur. Dans ce cas, le contrôle SqlDataSourceest chargé d'exécuter non seulement l'instruction SELECT pour récupérer les données, mais également les commandes DELETE (Supprimer) et UPDATE (Mettre à jour). À l'aide de la fenêtre des propriétés du contrôle SqlDataSource, j'ai ouvert l'éditeur des commande et propriétés de la propriété DeleteQueryet j'ai tapé l'instruction SQL nécessaire pour exécuter une opération de suppression.

Bb736724.rssagg_7(fr-fr,MSDN.10).gif

Notez que le paramètre que j'ai utilisé est indiqué sous la forme @original_feedId. Le contrôle SqlDataSource a une autre propriété intitulée OldValuesParameterFormatString qui spécifie l'apparence d'un paramètre d'entrée dans une requête. Le défaut de cette propriété est original_{0}, **{0}**étant un espace réservé à la valeur réelle du paramètre. Notez également que j'ai réglé la valeur Parameter source sur Controlet pointé la valeur ControlIDsur le contrôle GridView. J'ai suivi la même procédure pour ajouter une instruction UPDATE SQL dans la propriété UpdateQuery du contrôle SqlDataSource.

Jusqu'ici, tout allait bien. Toutefois, j'ai trouvé qu'il n'était pas facile d'ajouter des enregistrements à une base de données avec GridView. Vous pouvez résoudre ce problème de plusieurs façons (notamment en utilisant de manière créative le modèle de pied de page de GridView). Ma solution était d'utiliser le contrôle DetailsView qui, tout comme GridView, est un outil d'accès aux données polyvalent. Il vous permet de parcourir un ensemble de données en affichant un enregistrement à la fois, de mettre à jour ou supprimer l'enregistrement actuel ou d'ajouter un nouvel enregistrement. Vous pouvez également utiliser ce contrôle conjointement avec GridView pour implémenter une représentation de données maître/détail classique. Dans ce scénario, GridViewaffiche simplement une liste d'éléments qui, lorsqu'ils sont sélectionnés, sont affichés en détail dans le contrôle DetailsView. La flexibilité de ces contrôles vous donne beaucoup de choix dans la configuration de votre interface utilisateur pour vos pages Web. Pour ma part, j'ai bien aimé l'idée de disposer d'options de modification et suppression directement dans GridView tout en utilisant DetailsView pour ajouter de nouveaux enregistrements.

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Après avoir ajouté un contrôle DetailsView directement en dessous de GridView , j'ai réglé sa propriété DataSourceIDsur le contrôle SqlDataSource et je me suis assuré que seule sa propriété AutoGenerateInsertButtona été réglée sur True (vrai). Pour améliorer les performances, j'ai donné à la propriété EnabledViewStatela valeur False(fausse). J'ai ensuite ajouté le texte SQL nécessaire pour exécuter une instruction de base de données INSERT dans la propriété InsertQuerydu contrôle SqlDataSource.

Bb736724.rssagg_9(fr-fr,MSDN.10).gif

La seule différence entre la configuration de la propriété InsertQueryet les autres propriétés de requête du contrôle SqlDataSourceétait que le ControlID pour InsertQuerya été réglé sur le contrôle DetailsView(au lieu de GridView).

Ce qui est remarquable, c'est que j'ai implémenté toute la logique de gestion de la liste de flux sans avoir à écrire une seule ligne de code. Bien sûr, le téléchargement et la fusion des flux est une autre histoire, mais je voulais juste prendre une pause ici pour m'émerveiller devant la puissance et la simplicité de l'architecture de liaison de données ASP.NET 2.0.

Pour pouvoir afficher les flux RSS 2.0 agrégés, la première étape à franchir était de mettre en oeuvre un format de données commun. Vu que je ne devais afficher que quelques éléments de données standard (élément, description et lien), j'ai décidé d'utiliser un DataSetfortement typé pour enregistrer les données rassemblées de chaque flux. L'avantage principal de cette approche est que je pouvais aisément lier les données obtenues à un contrôle d'interface utilisateur. Après avoir ajouté un nouveau DataSetau projet, je l'ai ouvert dans le concepteur et créé un DataTablede quatre colonnes (voir ci-dessous).

Cliquez ici pour agrandir l'image
(cliquez sur l'image pour obtenir un zoom)

Outre les trois attributs d'éléments fondamentaux, j'ai également inclus une colonne appelée Feed(flux) pour enregistrer le nom du flux RSS source de sorte à pouvoir afficher ces informations sur la page Web.

Ensuite, j'ai ajouté deux méthodes privées au fichier de code du contrôle FeedManager. La première méthode, MergeRssFeeds, est appelée à partir du gestionnaire d'événements Loaddu contrôle. La première ligne de code crée une instance de niveau du DataSet AggregateRSSfortement typé servant à contenir les données extraites des flux RSS. Le code génère ensuite une itération sur les lignes du contrôle GridView, représentant chacun des flux RSS configurés. Dans la boucle

For

, le code appelle une deuxième méthode, AddRssFeed , transmettant le nom du flux RSS et son adresse 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>Error</h3><p>A
        Web exception occurred while merging the" +
        
        " RSS feeds.<br/>Make sure
            you have a valid connection to the " +
            
            "internet.</p><p><em>{0}<em></p>", wx.Message);
            Literal1.Visible = true;
            }}

A la fin de la boucle, le code règle la propriété DataSourcedu contrôle Repeatersur le DataSetalimenté puis appelle la méthode DataBind du Repeaterpour lier les données au contrôle.

La méthode d'assistance AddRssFeedse charge de l'essentiel du travail dans cette application. Le code extrait d'abord le flux RSS en utilisant la classe WebRequest et charge les données dans un XmlTextReader. Ensuite, il définit une boucle Whilepour générer une itération sur le flux XML. Pour rendre le code plus facile à expliquer, j'ai inclus les premières lignes de code ci-dessous.

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]
        While
        Finally
        If Not rssReader Is Nothing Then rssReader.Close()
        Try
        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();
                }}

À l'intérieur de la boucle Whileexterne, le code cherche des éléments appelés « item ». Ceci indique qu'un élément du flux RSS est le noeud actuel. Dans ce cas, le code crée un nouveau RssItemRowpour enregistrer les données de l'élément et crée ensuite un nouvel objet XmlReaderen utilisant la méthode ReadSubTree du XmlReader parent. Ce lecteur (appelé itemReader) renferme les données de l'élément RSS actuelles. Le code appelle la méthode Readdu lecteur interne XmlReaderpour rechercher tous les éléments de données pertinents. Une fois ces éléments trouvés, le code enregistre leur valeur dans la cellule appropriée du RssItemRow. À la fin de la boucle Whileinterne, le code appelle la méthode AddRssItemRowfortement typée du DataTablepour ajouter la ligne au 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
                    ' Truncate description to 100 characters
                    If newDescription.Length > 100 Then
                    newDescription = newDescription.Substring(0, 100) + " ..."
                    If
                    newRow.Description = newDescription
                    ElseIf ("link" = itemReader.LocalName) Then
                    newRow.Link = itemReader.ReadString
                    If
                    If
                    While
                    RssData.RssItem.AddRssItemRow(newRow)
                    itemCount = itemCount + 1
                    Finally
                    If Not itemReader Is Nothing Then itemReader.Close()
                    Try
                    If
                    ' Add only the first five items from each feed
                    If itemCount >= 5 Then Exit While
                    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();
                        //Truncate description to 100 characters
                        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();
                        }
                        // Add up to 5 of the items returns (this can be set in a
                        
                        // configuration file)
                        if (itemCount >= 5) break;
                        } }

C'est là tout le code dont j'ai besoin pour mettre en oeuvre l'agrégation RSS. Comme vous le voyez, la partie la plus délicate de l'application était la définition du paramètre XmlReaderet l'extraction des données de flux pertinentes. Mais une fois cette tâche accomplie, les remarquables capacités de liaison de données de ASP.NET ont contribué à faciliter énormément la création de cette application.

Cliquez ici pour agrandir l'image

(cliquez sur l'image pour obtenir un zoom)

L'étape suivante de ce projet est de placer les composants du gestionnaire de flux et les composants d'affichage de flux dans des contrôles séparés et d'ajouter une infrastructure ASP.NET 2.0 WebParts de services de personnalisation. À la prochaine fois.

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();
        }}
      

À l'intérieur de la boucle Whileexterne, le code cherche des éléments appelés « item ». Ceci indique qu'un élément du flux RSS est le noeud actuel. Dans ce cas, le code crée un nouveau RssItemRowpour enregistrer les données de l'élément et crée ensuite un nouvel objet XmlReaderen utilisant la méthode ReadSubTree du XmlReader parent. Ce lecteur (appelé itemReader) renferme les données de l'élément RSS actuelles. Le code appelle la méthode Readdu lecteur interne XmlReaderpour rechercher tous les éléments de données pertinents. Une fois ces éléments trouvés, le code enregistre leur valeur dans la cellule appropriée du RssItemRow. À la fin de la boucle Whileinterne, le code appelle la méthode AddRssItemRowfortement typée du DataTablepour ajouter la ligne au 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
        ' Truncate description to 100 characters
        If newDescription.Length > 100 Then
        newDescription = newDescription.Substring(0, 100) + " ..."
        If
        newRow.Description = newDescription
        ElseIf ("link" = itemReader.LocalName) Then
        newRow.Link = itemReader.ReadString
        If
        If
        While
        RssData.RssItem.AddRssItemRow(newRow)
        itemCount = itemCount + 1
        Finally
        If Not itemReader Is Nothing Then itemReader.Close()
        Try
        If
        ' Add only the first five items from each feed
        If itemCount >= 5 Then Exit While
        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();
        //Truncate description to 100 characters
        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();
        }
        // Add up to 5 of the items returns (this can be set in a

        // configuration file)
        if (itemCount >= 5) break;
        } }
      

C'est là tout le code dont j'ai besoin pour mettre en oeuvre l'agrégation RSS. Comme vous le voyez, la partie la plus délicate de l'application était la définition du paramètre XmlReaderet l'extraction des données de flux pertinentes. Mais une fois cette tâche accomplie, les remarquables capacités de liaison de données de ASP.NET ont contribué à faciliter énormément la création de cette application.

Cliquez ici pour agrandir l'image

(cliquez sur l'image pour obtenir un zoom)

L'étape suivante de ce projet est de placer les composants du gestionnaire de flux et les composants d'affichage de flux dans des contrôles séparés et d'ajouter une infrastructure ASP.NET 2.0 WebParts de services de personnalisation. À la prochaine fois.