Click here to Skip to main content
6,594,432 members and growing! (17,286 online)
Email Password   helpLost your password?
Enterprise Systems » SharePoint Server » Web Parts     Intermediate License: The Code Project Open License (CPOL)

RSS Reader webpart with tab support and asynchronous periodic data refresh using AJAX

By Madhur Ahuja

Creating RSS Reader webpart with tab support and asynchronous periodic data refresh using AJAX
C# (C# 1.0, C# 2.0, C# 3.0), ASP.NET, Ajax
Posted:23 Feb 2008
Views:28,304
Bookmarked:12 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
6 votes for this article.
Popularity: 2.02 Rating: 2.60 out of 5
3 votes, 50.0%
1
1 vote, 16.7%
2

3

4
2 votes, 33.3%
5

Download RSSRead.zip - 7.79 KB

Background

With the advent of SP1 of WSS 3.0 and MOSS 2007, developers can now make use of ASP.NET AJAX 1.0 (formerly ATLAS) in there applications. This is a good news for sharepoint community since they can use partial postbacks to update the backends(usually SQL 2005) in a flash rather than waiting for full postback of sharepoint, which can be painfully slow sometimes.

Introduction

This article describes how to build you’re an RSS Reader Web part which supports ASP.NET 2.0 AJAX 1.0 and makes use of AJAX Control Toolkit to implement multiple RSS readers in Tab Panels.

Software needed

  • MOSS 2007 SP1
  • Visual Studio 2005
  • ASP.NET 2.0 AJAX 1.0
  • AJAX Control Toolkit
Note:
Since the source code of this webpart is too big. I am not going to post and explain whole
code, instead I will focus on main areas like implantation of AJAX and RSS reader only. This
articles assumes knowledge of developing webparts with custom properties.
First you need to configure your MOSS web application for AJAX. I am not going to repeat it
here since this is already described in
This MSDN article: http://msdn2.microsoft.com/en-us/library/bb861898.aspx

Screenshots

This is what we are going to develop. Looks pretty cool ... isn't it:

screen21.JPG

screen31.JPG

About the Webpart

The input to our webpart will be multiple RSS url (maximum 4) and corresponding image
Url(optional) which be displayed next to RSS feeds.


Each RSS feed will be displayed in a separate tab and each item as a collapsible item with
description. The collapsibility is almost same as out of the box webpart except that we will make use of + and – sign to indicate collapsibility using client script.


We will Also have the custom properties for Update Interval – The interval after which the
webpart will update itself without postback.

Now its time to start coding the webpart. To separate the presentation from implementation, we will implement the RSS Reader in a different class than the webpart.


This class contains a static method GetFeeds which accepts a RSS URL(sharepoint only) and
returns a DataTable containing 4 columns with rows=number of items+2. The last two rows
contain the timestamp, title of the list and URL to the list.

Here is the code for the same, I have tried to make it as simple as possible:

class RSSRead
    {

        internal static System.Data.DataSet GetFeeds(string url)
        {
            System.Data.DataSet ds = new System.Data.DataSet();
            System.Data.DataTable dtFeeds = new System.Data.DataTable();
            dtFeeds.Columns.Add("Title");
            dtFeeds.Columns.Add("Url");
            dtFeeds.Columns.Add("PublishDate");
            dtFeeds.Columns.Add("Content");

            System.Data.DataTable info = new System.Data.DataTable();
            info.Columns.Add("Title");

            XmlDocument doc = null;
            try

            {

                    doc = new XmlDocument();
                    WebClient wc = new WebClient();
                    wc.UseDefaultCredentials = true;
                    string xml = wc.DownloadString(url);
                    xml = xml.Substring(3);
                  
                    doc.LoadXml(xml);
                }

                XmlNode nRoot = doc.DocumentElement;
                XmlNodeList nNodes = nRoot.SelectNodes("channel/item");

                System.Data.DataRow dr2 = info.NewRow();
                dr2["Title"] = 
nRoot.SelectSingleNode("channel/title").InnerText; ;
                info.Rows.Add(dr2);

                dr2 = info.NewRow();
                dr2["Title"] = 
nRoot.SelectSingleNode("channel/link").InnerText;
                info.Rows.Add(dr2);


                foreach (XmlNode node in nNodes)
                {
                    System.Data.DataRow dr = dtFeeds.NewRow();
                    dr["Title"] = node.SelectSingleNode("title").InnerText;
                    dr["Url"] = node.SelectSingleNode("link").InnerText;
                    dr["PublishDate"] = 
node.SelectSingleNode("pubDate").InnerText;
                    dr["PublishDate"] = 
Convert.ToDateTime(dr["PublishDate"].ToString()).ToUniversalTime().ToString
();
                    dr["Content"] = 
node.SelectSingleNode("description").InnerText;
                    dtFeeds.Rows.Add(dr);
                }

            }
            catch (Exception ee)
            {
                System.Data.DataRow dr2 = info.NewRow();
                dr2["Title"] = ee.Message;
                info.Rows.Add(dr2);
                ds.Tables.Add(info);
                return ds;

            }
            System.Data.DataRow dr1 = info.NewRow();
            dr1["Title"] = DateTime.Now.ToLongTimeString();
            info.Rows.Add(dr1);

            ds.Tables.Add(dtFeeds);
            ds.Tables.Add(info);

            return ds;

        }
    } 
Now to start, we will setup the custom properties for our webpart. I have taken a string arrays of length four to implement eight properties for each tab i.e. RSS Url and image Url. Coming to the structure of our webpart, We would have place one UpdatePanel control. Inside the UpdatePanel, we would have four TabPanel containing one label each for the
formatted output.

We will also have the UpdateProgress Control to display a simple animating image while the data is updating and a Timer Control to refresh the UpdatePanel whenever the time interval elapses.

So graphically , this would be the layout of webpart:
  • Webpart control
  • UpdatePanel control
  • TabContainer control
  • TabPanel control(s)
  • Label control(s)
  • UpdateProgress control
  • Timer control
Here is the code for declaring our class level variables (snipped):
        private string []_rssurl=new string[4];
        private string[] _rssimgurl = new string[4];
        TabPanel []tabs=new TabPanel[4];
        TabContainer tc;
        Label[] rsstext = new Label[4];
        UpdatePanel rsspanel;
        UpdateProgress rssprogress;
        Timer ajaxtimer;
        int _updateinterval=120;
        int _imgpanelwidth = 0;
        [DefaultValue("")]
        [WebPartStorage(Storage.Shared)]
        [FriendlyNameAttribute("1st RSS Feed URL")]
        [Description("Put 1st the RSS Feed URL")]
        [Browsable(true)]
        [XmlElement(ElementName = "RSSUrl")]
        public string RSSUrl
        {
            get

            {
                return _rssurl[0];
            }
            set
            {
                Uri url=new Uri(value,UriKind.Absolute);
                if (url.GetLeftPart(UriPartial.Path).Contains(rssstr))
                {
                    _rssurl[0] = value;
                }
            }
        }

        [DefaultValue("")]
        [WebPartStorage(Storage.Shared)]
        [FriendlyNameAttribute("1st Tab Image URL")]
        [Description("Put 1st Tab Imag URL")]
        [Browsable(true)]
        [XmlElement(ElementName = "RSSimgUrl")]
        public string RSSImgUrl
        {
            get

            {
                return _rssimgurl[0];
            }
            set
            {
                _rssimgurl[0] = value;

            }
        }
  
To work with AJAX, we need to declare the ScriptManager object. We will make
use of OnInit() function of webpart
To initialize ScriptManager and initialize the TabContainer and TabPanel.
The code below retrieves the already existing ScriptManager object on the page
and if the none is found, a new one is created. We also have a stylesheet
attached to TabContainer to style our control.
protected override void OnInit(EventArgs e)
        {
            // Let's find if the ScriptManager exists and add it if not

            ScriptManager scriptManager = ScriptManager.GetCurrent(Page);

            if (scriptManager == null)
            {
                scriptManager = new ScriptManager();
                scriptManager.EnablePartialRendering = true;
                scriptManager.ID = "sm";

                if (Page.Form != null)
                {
                    // Insert script manager after the web part manager

                    for (int controlIndex = 0; controlIndex < 
Page.Form.Controls.Count; controlIndex++)
                    {
                        if (Page.Form.Controls[controlIndex].GetType() == 
WebPartManager.GetType())
                        {
                            Page.Form.Controls.AddAt(controlIndex + 1, 
scriptManager);
                        }
                    }
                }
            } 


            tc = new TabContainer();
            tc.ID = "tc";
            tc.BorderWidth = Unit.Pixel(0);

            for (int i = 0; i < 4; ++i)
            {
                tabs[i] = new TabPanel();
                tabs[i].HeaderText = "Tab "+i.ToString();
                tabs[i].ID = "tabs" + i.ToString();
                tabs[i].BorderWidth = Unit.Pixel(0);
                tc.Tabs.Add(tabs[i]);
                
            }
            rssprogress = new UpdateProgress();
            rssprogress.ID = "rssprogress";
            rssprogress.ProgressTemplate = new 

MyTemplate(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
"RSSReaderAjax.activityanimation.gif"));
            this.Controls.Add(rssprogress);

            this.ChromeType = 
System.Web.UI.WebControls.WebParts.PartChromeType.None;

            base.OnInit(e);
        }
 

This is our webpart property panel

screen5.JPG

We will now implement the CreateChildControls() functions which initializes all the Controls and places the Controls in controls collection in the correct order. The function also checks if the RSS url is given to the webpart and if not, disables the tab which renders the Tab invisible.

   protected override void CreateChildControls()
        {
            base.CreateChildControls();
            #region Ajax_start

            EnsurePanelFix();

            rsspanel = new UpdatePanel();
            rsspanel.ID = "rsspanel";
            rsspanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
            rsspanel.ChildrenAsTriggers = true;

            ajaxtimer = new Timer();
            ajaxtimer.Enabled = true;
            ajaxtimer.ID = "ajaxtimer";
            ajaxtimer.Interval = UpdateInterval*1000;
           
            #endregion

            string content = "<script language="'javascript'"> " + togglescript 
+ "</script>";
            System.Web.UI.ScriptManager.RegisterClientScriptBlock(Page, 
this.GetType(), "madhur", content, false);
           
            plusimage = 

this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
"RSSReaderAjax.plus.gif");
            minusimage = 
this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
"RSSReaderAjax.minus.gif");

            string css = 
this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 

"RSSReaderAjax.StyleSheet.css");
            string link = "<link rel='stylesheet' type='text/css' href='" + 
css + "'/>";
            Page.Header.Controls.Add(new LiteralControl(link));


            rsspanel.ContentTemplateContainer.Controls.Add(tc);
            rsspanel.ContentTemplateContainer.Controls.Add(ajaxtimer);

            for (int i = 0; i < 4; ++i)
            {
                if (GetRSSUrl(i) == null)
                {
                    tc.Tabs[i].Enabled = false;
                    tabs[i].Controls.Add(new LiteralControl("Please specify 
the URL of the RSS feed in webpart properties.<br>"));

                }
                else

                {
                    rsstext[i] = new Label();
                    rsstext[i].ID = "rsstext" + i.ToString();
                    rsstext[i].Text = RSSBind(GetRSSUrl(i),i);
                    tabs[i].Controls.Add(rsstext[i]);

                }

            }
          
            this.Controls.Add(rsspanel);

            AjaxControlToolkit.UpdatePanelAnimationExtender anim = new 
UpdatePanelAnimationExtender();
            anim.ID = "anim";
            anim.TargetControlID = rsspanel.ID;
        }
  
Lets now implement our final function, which will take the RSS Url and will return a string containing the formatted RSS output. The returned string will make Use of image url and rss, which have been specified in the webpart. The function will call the GetFeeds() function defined above to retrieve the feeds and format it properly so that they are ready to be rendered.
   public  string RSSBind(string url,int index)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            System.Data.DataSet ds = RSSRead.GetFeeds(url);

            if (ds.Tables.Count == 1)
            {
                sb.Append("Error occured: " + 
ds.Tables[0].Rows[0][0].ToString());
                return sb.ToString();
            }

            System.Data.DataTable dtFeeds = ds.Tables[0];
            System.Data.DataTable info = ds.Tables[1];

            int count = 1;
            string divnonestyle = "style=display:none";

            string divid = string.Empty;
            string parentdivid = string.Empty;
            string funccall = string.Empty;
            sb.Append("<table>");
            sb.Append("<tr>");
            string s = GetRSSImage(index);
            if (!string.IsNullOrEmpty(s))
            {
                sb.Append("<td width='"+ImgPanelWidth+"' valign='top'>");
                sb.Append("<img src='" + GetRSSImage(index) + "' 
valign='top'/>");
                sb.Append("</td>");
            }
            sb.Append("<td>");
            foreach (System.Data.DataRowView drv in dtFeeds.DefaultView)
            {
                divid = this.ID+index.ToString()+ count.ToString();
               
                parentdivid = "ctl_" + divid;
                funccall = "javascript:ToggleItemDescription('" + divid + 

"','" + plusimage + "','" +minusimage + "')";

                sb.Append("<table>");
                sb.Append("<tr>");
                sb.Append("<td>");
                sb.Append("<img onclick=" + funccall + " valign=bottom 
border=0 style='cursor:hand;'id=\"" + parentdivid + "\" src=\"" + plusimage + 

"\"/>");
                sb.Append("</td>");
                sb.Append("<td>");
                sb.Append("<a href=\"" + funccall+"\">" + 
drv["Title"].ToString() + "</a>");
                sb.Append("</td>");
                sb.Append("</tr>");
                sb.Append("</table>");
                sb.Append("<div id=\"" + divid + "\"" + divnonestyle + ">");
                drv["Content"] = 
drv["Content"].ToString().Replace("<b>Body:</b>", string.Empty);
                drv["Content"] = drv["Content"].ToString().Replace('Â', ' ');
                sb.Append(drv["Content"].ToString());
                sb.Append("Published on: " + drv["PublishDate"].ToString());
                sb.Append("</div>");

 
                count++;
            }
            sb.Append("<a href=\"" + info.Rows[1][0].ToString() + 

"\"><br>Click here to View all items</a><br>");
            sb.Append("</td>");

            
            sb.Append("</tr>");
            sb.Append("</table>");


            int j=info.Rows[0][0].ToString().IndexOf(':');
            if (j != -1)
                tc.Tabs[index].HeaderText = 
info.Rows[0][0].ToString().Substring(j + 2);
            else

                tc.Tabs[index].HeaderText = info.Rows[0][0].ToString();

            return sb.ToString();

        }
 
I have tried to make the webpart as simple as possible. Some of the points to be worth noted:
  1. This webpart is designed only for consuming sharepoint RSS urls only. Although you are free to modify the code to suit your needs.
  2. The webpart does not take user permissions into account while reading the RSS Url.
I have included some screenshots of the webpart along with this article. You can view them here: Collapsed Expanded.
Click here to download the source code for this webpart.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Madhur Ahuja


Member
I am working in Wipro Technologies as a developer with expertises in Microsoft Office SharePoint products. My interests include working on ASP.NET, AJAX, Javascript Object Notation (JSON), XML web services, Algorithm Optimization, Design Patterns.
Occupation: Software Developer (Senior)
Company: Wipro Technologies
Location: India India

Other popular SharePoint Server articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 19 of 19 (Total in Forum: 19) (Refresh)FirstPrevNext
GeneralScriptManager PinmemberMauroMasucci3:02 15 Apr '09  
QuestionProject Source Code or Binary Pinmembergandevijay4:32 17 Feb '09  
Generalcould you send the complete solution or the binary file or webpart that could be installed on the site PinmemberMember 40457428:34 7 Oct '08  
GeneralRe: could you send the complete solution or the binary file or webpart that could be installed on the site PinmemberMadhur Ahuja8:37 7 Oct '08  
GeneralRe: could you send the complete solution or the binary file or webpart that could be installed on the site PinmemberSingh Ricky9:29 7 Oct '08  
GeneralRe: could you send the complete solution or the binary file or webpart that could be installed on the site Pinmembermad-tie6:38 29 Jan '09  
QuestionRe: could you send the complete solution or the binary file or webpart that could be installed on the site Pinmemberanoomathew3:41 30 Jun '09  
GeneralSorry to trouble you,I have a question Pinmemberliyuekd@163.com19:52 11 May '08  
GeneralSorry to trouble you for the Webcontrol -rsspanel of the project Pinmemberzeroneten22:54 21 Apr '08  
QuestionERROR Pinmemberiamsunil20050:45 14 Apr '08  
GeneralSorry for my question before. I got some progress. Pinmemberzeroneten17:21 14 Mar '08  
GeneralRe: Sorry for my question before. I got some progress. PinmemberMadhur Ahuja17:25 14 Mar '08  
GeneralRe: Sorry for my question before. I got some progress. Pinmemberzeroneten18:38 14 Mar '08  
GeneralRe: Sorry for my question before. I got some progress. PinmemberMadhur Ahuja19:38 14 Mar '08  
GeneralRe: Sorry for my question before. I got some progress. Pinmemberzeroneten23:17 14 Mar '08  
GeneralThanks for your article, but a question. Pinmemberzeroneten16:48 14 Mar '08  
GeneralRe: Thanks for your article, but a question. PinmemberMadhur Ahuja3:53 8 Apr '08  
GeneralThanks PinmemberRenny[RuS]23:27 29 Feb '08  
GeneralRe: Thanks PinmemberMadhur Ahuja0:45 1 Mar '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 23 Feb 2008
Editor:
Copyright 2008 by Madhur Ahuja
Everything else Copyright © CodeProject, 1999-2009
Web15 | Advertise on the Code Project