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 <item>
elements, and thus you specify the XPath expression as rss/channel/item.
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:
<asp:DataList ID="DataList1"
runat="server"
DataSourceID="XmlDataSource1">
<itemtemplate>
<b><%#XPath("title")%>
</b><br />
<i><%#XPath("description") %></i>
<%#XPath("pubDate")%>
<br />
<a href='<%#XPath("link")
%>'>Link</a>
<br />
<br />
</itemtemplate>
</asp:DataList>
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:
<system.web>
<profile>
<properties>
<add name="FeedNames"
type="System.String"/>
<add name="FeedURLs" type="System.String"/>
</properties>
</profile>
...
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:
...
<authentication mode="Forms"
/>
<authorization>
<deny users="?" />
</authorization>
</system.web>
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:
...
</system.web>
<location
path="NewUser.aspx">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
</configuration>
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
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Liftoff
News</title>
<link>http://liftoff.msfc.nasa.gov/</link>
<description>Liftoff
to Space Exploration.</description>
<language>en-us</language>
<pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
<lastBuildDate>Tue, 10 Jun 2003
09:41:01 GMT</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Weblog
Editor 2.0</generator>
<managingEditor>editor@example.com</managingEditor>
<webMaster>webmaster@example.com</webMaster>
<item>
<title>Star
City</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/
news-starcity.asp</link>
<description>How
do Americans get ready to work
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>.</description>
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/
2003/06/03.html#item573</guid>
</item>
<item>
<title>The
Engine That Does More</title>
<link>http://liftoff.msfc.nasa.gov/news/
2003/news-VASIMR.asp</link>
<description>Before
man travels to Mars, NASA hopes
to design new engines that will let us fly
through
the Solar System
more quickly. The proposed VASIMR
engine would do that.</description>
<pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/
2003/05/27.html#item571</guid>
</item>
<item>
<title>Astronauts'
Dirty Laundry</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/
news-laundry.asp</link>
<description>Compared
to earlier spacecraft, the
International Space Station has many luxuries,
but
laundry facilities are not one of them.
Instead,
astronauts have
other options.</description>
<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/
2003/05/20.html#item570</guid>
</item>
</channel>
</rss>
End Listing One