Streaming World Cup Tweets in Silverlight With a Few Lines of Code

The World Cup is on and there have been quite a few good Twitter mashups made for this event, probably the most popular being TweetBeat (and I’ve also developed one, Tweet For Your Team). In this post I’ll show how to build a simple service similar to TweetBeat using a publicly available real-time streaming service, Kwwika.

The application built in this short tutorial will be the following:

Why use a streaming service?

Getting tweets on a certain topic – in our case, the World Cup – can be done in three main ways:


Polling via the Twitter API requires quite the amount of work:

  1. You have to use the Twitter Search API and filter for the #worldcup tag (and perhaps other keywords)
  2. You have to handle errors from Twitter (in case the API is down at the moment of polling)
  3. You have to be aware not to poll too often: the Twitter Search API quota limitations are quite vaguely phrased, but it’s obvious that polling very often isn’t supported
  4. And finally, you have to handle filtering the results on the client side: basically making sure messages aren’t duplicated



The Twitter Streaming API requires to implementing an application consuming the Twitter stream. Unfortunately at the moment I’m unaware of any Silverlight solutions for this, however based on a tutorial of consuming the Twitter API in Python, this method should be easier to implement then the polling version. This post does not focus on implementing the application this way though.

Third party streaming is probably the fastest and easiest way to develop such an application. These services take care of polling/streaming the tweets from Twitter and stream it to the application. Currently the only such service I’m aware of is Kwwika. (Kosmix seem to use such streaming themselves, but currently don’t offer any service to the public).

Streaming World Cup Tweets – With a Few Lines of Code

Using the Kwwika Silverlight API is surprisingly easy. There are three steps to do in order to start receiving tweets: initialize a connection, subscribe to a channel and handle the callback when tweets arrive.

1. Initalizing the connection

The code for the initalization is as follows:

string apiKey = "7d476620-8a67-11df-a4ee-0800200c9a66"; // Demo key. To use other channels than the one in this demo, request an API key at kwwika.com 
string domain = "gergelyorosz.com"; // Your application domain
Kwwika.Service.ConnectionCreated += new Kwwika.ConnectionCreatedEventHandler(Service_ConnectionCreated);
Kwwika.Service.Connect(apiKey, domain);

During initialization a callback method has to be provided that’s called once the connection is ready.

2. Subscribing to a stream

Subscribing for a stream (in this case the uncategorized World Cup Tweets) is as follows:

public partial class MainPage : UserControl, Kwwika.ISubscriptionListener
{
    private Kwwika.IConnection _kwwikaConnection;
 
    /// 
    /// Called when thte Kwwika connection has been initialized
    /// 
    void Service_ConnectionCreated(Kwwika.ConnectionCreatedEventArgs e)
    {
        _kwwikaConnection = e.Connection;
        // Subscribe to the topic to be pushed: for now let's choose the World Cup "Other" topic
        _kwwikaConnection.Subscribe("/KWWIKA/TWITTER/SEARCHES/WC2010/OTHER", this);
    }
}

A Kwwika.ISubscriptionListener type object can subscribe to a channel through the connenction object. For the simplicity of the code I’ve made the MainPage UserControl implement the ISubscriptionListener interface and have subscribe to the channel.

3. Handling incoming tweets

After having subscribed, the ISubscriptionListener objects two methods, TopicUpdated and TopicError methods get called whenever a message has arrived. The code for this is as follows:

    /// 
    /// Kwwika.ISubscriptionListener implementation: called when new data has been pushed
    /// 
    public void TopicUpdated(Kwwika.ISubscription sub, Dictionary values, bool isImage)
    {
        // If a new result comes in, parse it and insert it!
        if (values.ContainsKey("Text"))
        {
            var message = new TwitterMessage()
            {
                Text = values["Text"],
                ScreenName = values["ScreenName"],
                CreatedAt = values["CreatedAt"],
                UserFollowersCount = values["UserFollowersCount"],
                Id = values["Id"],
                UserProfileImage = new Uri(values["UserProfileImageUrl"], UriKind.Absolute),
            };
            this.Dispatcher.BeginInvoke(new Action(() => { _twitterMessages.Insert(0, message); }));
        }
    }
 
    /// 
    /// Kwwika.ISubscriptionListener implementation: called when an error occured during pushing the data
    /// 
    ///
 
    ///
 
    public void TopicError(Kwwika.ISubscription sub, Kwwika.CommandErrorType error)
    {
        // TODO: handle if an error occurs during the streaming
    }

Streaming World Cup Tweets: the Complete Source Code

After taking care of creating a connection, subscribing to it and handling message updates, all that’s left is updating the UI. This I’ve done using a ListBox that has an ObservableCollection of twitter messages bound to it. The source of the backend is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
 
namespace TwitterPushSearch
{
public partial class MainPage : UserControl, Kwwika.ISubscriptionListener
{
    /// <summary>
    /// Collection of twitter messages 
    /// </summary>
    private ObservableCollection<TwitterMessage> _twitterMessages = new ObservableCollection<TwitterMessage>();
 
    private Kwwika.IConnection _kwwikaConnection;
 
    public MainPage()
    {
        InitializeComponent();
 
        _twitterMessages.CollectionChanged += (e, s) => { TwitterMessages.UpdateLayout(); };
        TwitterMessages.ItemsSource = _twitterMessages;
 
        // Init the push connection
        string apiKey = "7d476620-8a67-11df-a4ee-0800200c9a66"; // Demo key. To use other channels than the one in this demo, request an API key at kwwika.com 
        string domain = "gergelyorosz.com"; // Your application domain
        Kwwika.Service.ConnectionCreated += new Kwwika.ConnectionCreatedEventHandler(Service_ConnectionCreated);
        Kwwika.Service.Connect(apiKey, domain);
    }
 
    /// <summary>
    /// Called when thte Kwwika connection has been initialized
    /// </summary>
    void Service_ConnectionCreated(Kwwika.ConnectionCreatedEventArgs e)
    {
        _kwwikaConnection = e.Connection;
        // Subscribe to the topic to be pushed: for now let's choose the World Cup "Other" topic
        _kwwikaConnection.Subscribe("/KWWIKA/TWITTER/SEARCHES/WC2010/OTHER", this);
    }
 
    /// <summary>
    /// Kwwika.ISubscriptionListener implementation: called when new data has been pushed
    /// </summary>
    public void TopicUpdated(Kwwika.ISubscription sub, Dictionary<string, string> values, bool isImage)
    {
        // If a new result comes in, parse it and insert it!
        if (values.ContainsKey("Text"))
        {
            var message = new TwitterMessage()
            {
                Text = values["Text"],
                ScreenName = values["ScreenName"],
                CreatedAt = values["CreatedAt"],
                UserFollowersCount = values["UserFollowersCount"],                   
                Id = values["Id"],
                UserProfileImage = new Uri(values["UserProfileImageUrl"], UriKind.Absolute),
            };
            this.Dispatcher.BeginInvoke(new Action(() => { _twitterMessages.Insert(0, message); }));
        }
    }
 
    /// <summary>
    /// Kwwika.ISubscriptionListener implementation: called when an error occured during pushing the data
    /// </summary>
    /// <param name="sub"></param>
    /// <param name="error"></param>
    public void TopicError(Kwwika.ISubscription sub, Kwwika.CommandErrorType error)
    {
        // TODO: handle if an error occurs during the streaming
    }
}
 
public class TwitterMessage
{
    public string Text { get; set; }
 
    public string ScreenName { get; set; }
 
    public string CreatedAt { get; set; }
 
    public string UserFollowersCount { get; set; }
 
    public string Id { get; set; }
 
    public Uri UserProfileImage { get; set; }
}
}

The code for the XAML:

<UserControl x:Class="TwitterPushSearch.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
 
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical"  Width="400">
    <TextBlock FontWeight="Bold">The latest World Cup tweets:</TextBlock>
    <ScrollViewer Height="400">
        <ListBox x:Name="TwitterMessages" BorderThickness="0">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border x:Name="MessageBorder" BorderThickness="1" BorderBrush="Gray" Padding="5,5,5,5">
                        <StackPanel Orientation="Vertical" Width="350" Margin="0,0,0,10">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                <Border BorderThickness="1" BorderBrush="Gray" Margin="5,5,5,5" VerticalAlignment="Top">
                                    <Image Source="{Binding UserProfileImage}" Width="48" Height="48"/>
                                </Border>
                                <TextBlock Text="{Binding Text}" Width="210" TextWrapping="Wrap" Margin="0,5,5,5" VerticalAlignment="Top"/>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <HyperlinkButton Content="{Binding ScreenName}" NavigateUri="{Binding TwitterUserUrl}" TargetName="_blank" FontWeight="Bold" Margin="60,0,0,0"/>
                                <TextBlock Margin="5,0,0,0"> at</TextBlock>
                                <TextBlock Text="{Binding CreatedAtText}" Margin="5,0,0,0"/>
                            </StackPanel>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>            
        </ListBox>
    </ScrollViewer>
</StackPanel>
</UserControl>

The source for the complete application can be downloaded here: Twitter Push Client.zip.

Streaming Real-Time Data: Not Just World Cup Tweets, Not Just Tweets

Kwwika, the third party service I’ve used in this application is of course not limited to streaming only World Cup tweets, what’s more, not even limited to just tweets. They provide a service allowing distribution of any data real-time on numerous platforms: may that be tweets on a specific topic, chat messages, breaking news or any other real-time usage.

If you’re interested, feel free to contact them on usage terms, pricing and feature requests: I’ve found them to be extremely helpful and responsive.

5 Responses to Streaming World Cup Tweets in Silverlight With a Few Lines of Code
  1. Trackback: DotNetShoutout
    Streaming World Cup Tweets in Silverlight With a Few Lines of Code... Thank you for submitti... dotnetshoutout.com/Streaming-World-Cup-Tweets-in-Silverlight-With-a-Few-Lines-of-Code
  2. increase followers on twitter... [...]Greg Does IT » Blog Archive » Streaming Wo... buyingrealtwitterfollowers.com/category/pay-for-twitter-followers
  3. gold world of warcraft... [...]Greg Does IT » Blog Archive » Streaming World Cup... wow77.com/Imagesinfo.aspx?id=66