Friday 11 February 2011

Bird Seed (A Simple Tweet Reader)

This post shows how to easily integrate twitter updates into your ASP.NET web site using LINQ to XML and the Repeater control.

Twitter has a flexible collection of mechanisms for accessing information in a variety of formats such as a simplified RSS style XML feed or a plain XML feed that provides a richer set of information about a user and their updates. I am going to use the latter, although for brevity I am just going to pull the date, message and user from the user_timeline method which can be retrieved from http://twitter.com/statuses/user_timeline/user_id.xml (replacing user_id with your twitter handle). To read this information I am going to use LINQ to XML (available in the .NET Framework Version 3.5) as this API simplifies working with XML data without having to use additional language syntax like XPath. Finally, to format the output I am going to bind the data to a Repeater Control (which will reside in a web user control that we can set properties on).

Create a new web user control:

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="BirdSeed.ascx.vb" Inherits="BirdSeed" %>

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <p>
            <asp:Label ID="NameLabel" runat="server" Text='<%#Eval("Name")%>'></asp:Label>
            <br />
            <asp:Label ID="DateCreatedLabel" runat="server" Text='<%#Eval("DateCreated", "{0:dd/MM/yyyy HH:mm}")%>'></asp:Label>
            <br />
            <asp:Label ID="MessageLabel" runat="server" Text='<%#Eval("Message")%>'></asp:Label>
        </p>
    </ItemTemplate>
</asp:Repeater>

Add a UserID property to the user control's code behind and launch the request in its Page_Load method:

Imports System.Net
Imports System.Xml
Imports System.Xml.Linq
Imports System.Linq

Partial Class BirdSeed
    Inherits System.Web.UI.UserControl

    Dim _UserID As String = Nothing
    Public Property UserID() As String
        Get
            Return _UserID
        End Get
        Set(ByVal value As String)
            _UserID = value
        End Set
    End Property

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then

            Dim url As String = String.Format("http://twitter.com/statuses/user_timeline/{0}.xml", UserID)

            Using wr As WebResponse = WebRequest.Create(url).GetResponse()

                Using reader As XmlReader = XmlReader.Create(wr.GetResponseStream())

                    Dim xDoc As XDocument = XDocument.Load(reader)

                    Dim query = From el In xDoc.Descendants("status") _
                                Select New With { _
                                    .DateCreated = ParseDateTime(GetValue(el, "created_at")), _
                                    .Message = ParseLinks(GetValue(el, "text")), _
                                    .Name = GetUserName(el) _
                                }

                    Repeater1.DataSource = query.ToList
                    Repeater1.DataBind()

                End Using

            End Using

        End If

    End Sub

    Private Function GetUserName(ByVal element As XContainer) As String

        Dim query = From el In element.Descendants("user") _
                    Select New With { _
                        .Name = GetValue(el, "name") _
                    }

        Return query.ToList.Item(0).Name

    End Function

    Private Function GetValue(ByVal element As XContainer, ByVal key As String) As String
        Dim el = element.Element(key)
        Return If(el Is Nothing, "", el.Value)
    End Function

    Public Shared Function ParseDateTime(ByVal dt As String) As DateTime

        Dim dayOfWeek As String = dt.Substring(0, 3).Trim()
        Dim month As String = dt.Substring(4, 3).Trim()
        Dim dayInMonth As String = dt.Substring(8, 2).Trim()
        Dim time As String = dt.Substring(11, 9).Trim()
        Dim offset As String = dt.Substring(20, 5).Trim()
        Dim year As String = dt.Substring(25, 5).Trim()

        Return DateTime.Parse(String.Format("{0}-{1}-{2} {3}", dayInMonth, month, year, time))

    End Function

    Private Function ParseLinks(ByVal text As String) As String

        Dim pattern As String = "(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?"

        Dim matchDelegate As New MatchEvaluator(AddressOf LinkMatchHandler)
        Dim regx As Regex = New Regex(pattern, RegexOptions.IgnoreCase)

        Return regx.Replace(text, matchDelegate)

    End Function

    Private Function LinkMatchHandler(ByVal m As Match) As String
        Return String.Format("<a href=""{0}"">{0}</a>", m)
    End Function

End Class

Finally, register the user control on your application page and make an instance of it (passing along a twitter handle in the UserID property).

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%@ Register TagPrefix="uc" TagName="BirdSeed" Src="~/BirdSeed.ascx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Bird Seed</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <uc:BirdSeed ID="BirdSeed1" runat="server" UserID="dgzyky" />
    
    </div>
    </form>
</body>
</html>

You can limit the number of results by simply setting the repeaters data source like so:

Repeater1.DataSource = query.Take(5).ToList

There you have it, a simple tweet reader using ASP.NET, LINQ to XML and the Repeater Control.

Demo

View a live demo at http://code.zyky.com/birdseed/

Code

Download the Source Code

No comments:

Post a Comment