CoverStory
LANGUAGES: VB.NET
ASP.NET VERSIONS: 2.0
Keep It Simple
Create a Web-based RSS Reader Using ASP.NET 2.0
By Wei-Meng Lee
Reading blogs is one of the activities you need to do on a regular basis if you want to stay in-the-know in today s fast-paced technology world. Most people use a Windows-based RSS reader to aggregate all the blogs that interest them. However, the downside of this approach is that when one moves from one computer to another, all the subscribed feeds on one computer are no longer available on the other computer (one must manually export the subscription on one computer and import it into the other computer). A better solution would be to use a Web-based RSS reader so all the feeds are stored on a Web server and, hence, can be accessed on any computer.
To that end, I set out to build my own Web-based RSS reader using ASP.NET 2.0. The many new features in ASP.NET 2.0 made this project really simple. Here are the features I used:
- New security controls to authenticate users.
- Profile properties to store users subscribed feeds.
- XmlDataSource and DataList controls to databind RSS feeds for display purposes.
Creating the RSS Reader Page
Launch Visual Studio 2005 and create a new Web site project. Name the project RSSReader. Populate the Default.aspx page with the security controls shown in Figure 1. By default, the LoginView control displays the AnonymousTemplate view. This is the view all unauthenticated users see. In this view, type the string Please log in: and add a LoginStatus control. When a user is authenticated, you should display the username of the user. Hence, in the Smart Tag of the LoginView control, switch to the LoggedInTemplate view and type the string You are logged in as and add a LoginName and a LoginStatus control. Add to Default.aspx the other controls shown in Figure 2.
Figure 1: Adding the security
controls to the top of the page.
Figure 2: Populating the rest of
Default.aspx.
In the Smart Tag of the ListBox control, check the Enable AutoPostback checkbox so that every time a user clicks on an item within it, a postback occurs. Also, set the Forecolor property of txtFeedTitle to Red and its Font,Bold property to True.
Right-click on the project name in Solution Explorer and select Add New Item. Select XML File and name it RSS.xml. Populate the RSS.xml document (as shown in Listing One). This XML file contains a sample RSS document and is used to bind to the XmlDataSource and DataList controls.
In the Choose Data Source dropdown list in the DataList Smart Tag, select XmlDataSource1. In the Smart Tag of the XmlDataSource control, click the Configure Data Source link and enter the settings shown in Figure 3.
Figure 3: Loading the XmlDataSource
control with an XML document.
The XPath expression specifies the subset of the XML file in
which you are interested. In this case, you are only interested in the
Switch to Source View for Default.aspx and add the following code highlighted in bold to configure the DataList control so that it will display the appropriate sections of the XML file:
DataSourceID="XmlDataSource1"> <%#XPath("title")%>
<%#XPath("description") %> <%#XPath("pubDate")%>
Apply the Sand & Sky theme to the DataList control using Auto Format in the DataList Smart Tag. The Default.aspx page will now look like Figure 4. (Note: I made some additional settings to align the ListBox control to the top of the table cell as well as to resize the DataList control. Download the sample code to obtain the additional settings.)
Figure 4: The Default.aspx page.
For this application, all the feeds subscribed by the user will be saved using the new Profile object in ASP.NET 2.0. Using the Profile object, you can save personalized information related to each user of your application.
In Web.config, add the following Profile properties highlighted in bold:
...
Here, you defined two Profile properties: FeedNames and FeedURLs. The FeedNames property is used to store the names of feeds to which the user is subscribed. The FeedURLs property stores the URL of the corresponding feeds. The table in Figure 5 shows how the properties look when the user subscribes to two feeds. The names and URLs are separated by a semi-colon ( ; ) character.
Property |
Value |
FeedNames FeedURLs |
CNET Reviews;Engadget; http://www.cnet.com/4914-6022_1-0.xml?author=Wood:Molly&maxhits=5;http://www.engadget.com/rss.xml; |
Figure 5: The values of the Profile properties.
We are now ready to write the code for the application. Switch to the code view of Default.aspx and import the following namespaces:
Imports System.Net
Imports System.IO
Imports System.Xml
In the Page_Load event, you will load the list of subscribed feeds from the Profile properties, then populate the ListBox controls with the subscribed feeds (see Figure 6).
Protected Sub Page_Load( _
ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
btnSubscribe.Enabled = False
'---When the form loads for the first time...---
Dim FeedNames() As String = Profile.FeedNames.Split(";")
Dim FeedURLs() As String = Profile.FeedURLs.Split(";")
'---Populate the ListBox control---
For i As Integer = 0 To FeedNames.Length - 2
Dim listItem As New ListItem(FeedNames(i), FeedURLs(i))
lstSubscriptions.Items.Add(listItem)
Next
'---Select the first item in the ListBox---
If lstSubscriptions.Items.Count > 0 Then
lstSubscriptions.SelectedIndex = 0
lstSubscriptions_SelectedIndexChanged(Nothing, Nothing)
End If
End If
End Sub
Figure 6: Populate the ListBox controls with the subscribed feeds.
The Verify Feed button loads the RSS feed using the URL specified in the txtRssURL TextBox control. It calls the LoadFeed function to load the RSS document (see Figure 7).
Protected Sub btnVerifyFeed_Click( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnVerifyFeed.Click
'---Load the RSS feed XML document
and extract the title---
txtFeedTitle.Text = LoadFeed(txtRssURL.Text)
If txtFeedTitle.Text = String.Empty Then
DisplayError("Feed did not load correctly.")
Else
btnSubscribe.Enabled = True
End If
End Sub
Figure 7: The LoadFeed function loads the RSS document.
The DisplayError subroutine displays a window on the client side informing the user of an error:
Protected Sub DisplayError(ByVal msg As String)
'---Display a window on the client side---
Dim script As String = _
"alert('" & msg & "');"
Page.ClientScript.RegisterClientScriptBlock( _
Me.GetType, "Key", script, True)
End Sub
The LoadFeed function sends a request to the server using the HttpWebRequest object (see Figure 8). It uses the SendRequest and GetResponse functions (which are defined shortly) to obtain the RSS document. Once the RSS document is obtained, it uses the XPath expression channel/title to fetch the title of the feed. The LoadFeed function returns the title of the feed.
Public Function LoadFeed( _
ByVal URI As String) As String
Dim req As HttpWebRequest
Dim xmlDoc As XmlDocument = Nothing
Try
req = SendRequest(URI, "GET")
Dim xmlData As String = GetResponse(req)
xmlDoc = New XmlDocument()
xmlDoc.LoadXml(xmlData)
'---Select the title of the document---
Dim titleNode As XmlNode = _
xmlDoc.DocumentElement.SelectSingleNode( _
"channel/title")
Return titleNode.InnerText
Catch ex As Exception
Return String.Empty
End Try
End Function
Figure 8: LoadFeed in action.
The SendRequest and GetResponse functions use the HttpWebRequest and HttpWebResponse objects to send a request and receive a response over HTTP (see Figure 9).
Public Function SendRequest( _
ByVal URI As String, _
ByVal requestType As String) As HttpWebRequest
Dim req As HttpWebRequest = Nothing
Try
'---Creates a HTTP request---
req = HttpWebRequest.Create(URI)
req.Method = requestType '---GET or POST---
Catch ex As Exception
Throw New Exception("Error")
End Try
Return req
End Function
Public Function GetResponse( _
ByVal req As HttpWebRequest) As String
Dim body As String = String.Empty
Try
'---Get a response from server---
Dim resp As HttpWebResponse = req.GetResponse()
Dim stream As Stream = resp.GetResponseStream()
'---Use a StreamReader to read the response---
Dim reader As StreamReader = _
New StreamReader(stream, Encoding.UTF8)
body = reader.ReadToEnd()
stream.Close()
Catch ex As Exception
Throw New Exception("Error")
End Try
Return body
End Function
Figure 9: Send a request and receive a response over HTTP.
Once a feed is verified and its title retrieved, the user can subscribe to the feed by clicking the Subscribe button. The Subscribe button adds a new feed to the ListBox control and, at the same time, adds the new feed name and URL to the Profile properties (FeedNames and FeedURLs); see Figure 10.
Protected Sub btnSubscribe_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnSubscribe.Click
'---If user did not enter an URL---
If txtRssURL.Text = String.Empty Then
DisplayError("Please enter the feed URL.")
Exit Sub
End If
'---Bind the XmlDataSource control to the URL specified---
XmlDataSource1.DataFile = txtRssURL.Text
'---Add to the ListBox control---
Dim listItem As New ListItem( _
Trim(txtFeedTitle.Text), Trim(txtRssURL.Text))
'---If no duplicate entry in the ListBox---
If Not lstSubscriptions.Items.Contains(listItem) Then
lstSubscriptions.Items.Add(listItem)
lstSubscriptions.SelectedIndex = _
lstSubscriptions.Items.Count - 1
'---Add to the Profile properties---
Profile.FeedNames += Trim(txtFeedTitle.Text) & ";"
Profile.FeedURLs += Trim(txtRssURL.Text) & ";"
Else
DisplayError("Feed is already subscribed.")
End If
btnSubscribe.Enabled = False
End Sub
Figure 10: Clicking the Subscribe button adds a new feed to the ListBox control and adds the new feed name and URL to FeedNames and FeedURLs.
When the user clicks on an item in the ListBox control, the DataList control should now be bound to the current selected feed:
Protected Sub lstSubscriptions_SelectedIndexChanged( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles lstSubscriptions.SelectedIndexChanged
Try
'---Bind the XmlDataSource control to the selected
' item URL---
XmlDataSource1.DataFile = _
lstSubscriptions.SelectedItem.Value
Catch ex As Exception
DisplayError("Error displaying the feed.")
End Try
End Sub
To unsubscribe a feed, the user selects an item in the ListBox control, then clicks the Unsubscribe button. The Unsubscribe button will remove the selected feed from the two Profile properties and then remove the selected item from the ListBox control (see Figure 11).
Protected Sub btnUnsubscribe_Click( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnUnsubscribe.Click
Try
'---Remove the unsubscribed URL from the Profile
' properties---
Profile.FeedNames = _
Profile.FeedNames.Remove( _
Profile.FeedNames.IndexOf( _
lstSubscriptions.SelectedItem.Text), _
lstSubscriptions.SelectedItem.Text.Length + 1)
Profile.FeedURLs = _
Profile.FeedURLs.Remove( _
Profile.FeedURLs.IndexOf( _
lstSubscriptions.SelectedItem.Value), _
lstSubscriptions.SelectedItem.Value.Length + 1)
'---Remove the item from the ListBox control---
lstSubscriptions.Items.Remove( _
lstSubscriptions.SelectedItem)
'---Select the first item in the ListBox---
If lstSubscriptions.Items.Count > 0 Then
lstSubscriptions.SelectedIndex = 0
lstSubscriptions_SelectedIndexChanged(Nothing, Nothing)
Else
'---ListBox is empty; bind to default RSS---
XmlDataSource1.DataFile = "~/RSS.xml"
DataList1.DataBind()
End If
Catch ex As Exception
End Try
End Sub
Figure 11: Unsubscribe a feed.
Creating the Login Page
By default, the authentication mode used in ASP.NET Web applications is Windows authentication. However, this is not the ideal case for Internet users. Instead, you should change the authentication mode to Forms.
In Web.config, set the mode attribute of the authentication element to Forms and add the authorization element to deny access to all anonymous (unauthenticated) users:
...
In Solution Explorer, right-click on the project name and select Add New Item. Select the Web Form template and name it Login.aspx. Populate the Login.aspx Web form with the Login and HyperLink controls, as shown in Figure 12. You can use the Auto Format link in the Smart Tag of the control to apply the Elegant scheme.
Figure 12: The Login.aspx page.
Also, set the NavigateUrl property of the HyperLink control to ~/NewUser.aspx (you ll see its use in the next section).
Registering a New User
There are a couple of ways to add user accounts to your application. One way would be to use the Web Site Administration Tool (Website | ASP.NET Administration) to directly create user accounts. However, this method requires that you manually create accounts before the users can use your application. A better way would be to let the users create their own accounts. Hence, you should create a new form for users to create their own user account.
In Solution Explorer, right-click on the project name and select Add New Item. Select the Web Form template and name it NewUser.aspx. Add the CreateUserWizard control to the NewUser.aspx page (see Figure 13).
Figure 13: The NewUser.aspx page.
Set the ContinueDestinationPageURL property of the CreateUserWizard control to ~/Default.aspx . In addition, you need to add the following sections highlighted in bold to Web.config so that anonymous users can access this page:
...
Testing the Application
You are now ready to test the application. Press F5 in Visual Studio 2005 and the first page to load will be Login.aspx (see Figure 14). As a first-time user, you should click the Register link to create a new account for yourself.
Figure 14: The Login page.
The NewUser.aspx page will now load (see Figure 15). Enter the required information and click Create User. If the account is created successfully, you will be redirected to another page indicating that your account has been successfully created. Click the Continue button.
Figure 15: Creating a new user account.
You will now be directed to the main page of your application, Default.aspx (see Figure 16). Notice that the DataList control is bound to the RSS.xml file.
Figure 16: The main page of the
application.
Enter a feed URL (such as http://www.engadet.com/rss.xml) and click the Verify Feed button (see Figure 17). If the feed loads successfully, you ll see the feed title displayed in red. Click the Subscribe button to subscribe to the feed.
Figure 17: Subscribing to a feed.
You can repeat the above process multiple times and subscribe to multiple feeds. Figure 18 shows the application with seven subscribed feeds. When you log out (by clicking on the Logout link at the top of the page) and log in again, the feeds will still be there.
Figure 18: Subscribing to multiple
feeds.
Conclusion
You now have a working Web-based RSS Reader. As you can see, a lot of plumbing code in ASP.NET has already been written for you (such as saving and retrieving values from Profile properties, as well as the functionality of the security controls) so you can focus on writing the core logic of your application. Download the sample application and take it for a spin!
The sample code accompanying this article is available for download.
Wei-Meng Lee (http://weimenglee.blogspot.com) is a technologist and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. Wei-Meng speaks regularly at international conferences and has authored and co-authored numerous books on .NET, XML, and wireless technologies, including ASP.NET 2.0: A Developer s Notebook and Visual Basic 2005 Jumpstart (both from O Reilly Media, Inc.). Wei-Meng is also a Microsoft MVP.
Begin Listing One a sample RSS document
http://liftoff.msfc.nasa.gov/
09:41:01 GMT
http://liftoff.msfc.nasa.gov/news/2003/
news-starcity.asp
with Russians aboard the International Space
Station? They take a crash course in culture,
language and protocol at Russia's <a href=
"http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star
City</a>.
2003/06/03.html#item573
http://liftoff.msfc.nasa.gov/news/
2003/news-VASIMR.asp
to design new engines that will let us fly through
the Solar System more quickly. The proposed VASIMR
engine would do that.
2003/05/27.html#item571
http://liftoff.msfc.nasa.gov/news/2003/
news-laundry.asp
International Space Station has many luxuries, but
laundry facilities are not one of them. Instead,
astronauts have other options.
2003/05/20.html#item570
End Listing One