Cross-Domain requests in Silverlight and using Yahoo Pipes as a proxy

Last week, I have been developing this silverlight twitter application and was struck at a point, where I needed to pull RSS feeds from twitter. The code will always throw a Security Exception again and again. After digging a bit, I found out that silverlight doesn’t allow cross-domain calls to any domain you want.

This policy has been enforced to prevent session riding, for further details look this Karen Corby’s blog post on cross domain requests.

Turns out that in silverlight, HTTP requests to non-original domains are allowed if the server has exclusively allowed to accept requests. The primary way of enabling cross domain calls is through a policy file placed at the root of the server.  Two types of policy files are supported:

  1. Silverlight Cross Domain Policy File (clientaccesspolicy.xml)
  2. (A subset of the) Flash Cross Domain Policy File (crossdomain.xml)

Now, the problem is that twitter don’t have policy files placed in the server root. Possible way to get around this is to use a proxy for requests. you can make a proxy on your server, that can on application request, fetch the RSS data from twitter and send it back to your application. EASY!

but what if, you don’t want your own server proxy…

reasons:

  • you will have to add a policy file to your server root
  • that will cause increase in the server bandwidth usage and server stress
  • it’s hell lot of work

simple! use Yahoo Pipes, why?

  • Its easy
  • because, they allow you to request RSS feeds from other sites (multiple sites in one request)
  • they have cross-domain policy files placed on there server roots, that means your silverlight application will be able to fetch the Twitter data via a yahoo pipe

What is a yahoo pipe?

Content-source: http://pipes.yahoo.com/pipes/

Pipes is a powerful composition tool to aggregate, manipulate, and mashup content from around the web.

Like Unix pipes, simple commands can be combined together to create output that meets your needs:

  • combine many feeds into one, then sort, filter and translate it.
  • geocode your favorite feeds and browse the items on an interactive map.
  • power widgets/badges on your web site.
  • grab the output of any Pipes as RSS, JSON, KML, and other formats.

simply speaking, a yahoo pipe is url like this:

http://pipes.yahooapis.com/pipes/pipe.info?_id=bas782j290jq9dd2nmaklfhj93ji9d3j

you design its behaviour on a design surface

image

So, a yahoo pipe can be designed to take single/multiple feed URLs, fetch the feeds and provide an aggregated feed which can be consumed by your silverlight application under cross domain policy.

further, you can provide test data and see results right there.

Run it and get the aggregated RSS URL from the run screen.

The pipe, I used looks like this

http://pipes.yahooapis.com/pipes/pipe.run?_id=f0cf1b0851bd8243dbf8bd63c07b8d11&_render=rss&feedUrl=<some_feed_url>

image

Now fetching the data in your silverlight application is damn easy…

 

private string proxy = "http://pipes.yahooapis.com/pipes/pipe.run?_id=f0cf1b0851bd8243dbf8bd63c07b8d11&_render=rss&feedUrl=";
private string feedUrl = "http://twitter.com/statuses/user_timeline/22100709.rss";

void DownloadFeed()
{
            string url = proxy + feedUrl;
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
            request.Method = "GET";
            request.BeginGetResponse(new AsyncCallback(ResponseHandler), request);
}

void ResponseHandler(IAsyncResult asyncResult)
{
            try
            {
                HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream stream = response.GetResponseStream();
                    int len = 1024;
                    byte[] buf = new byte[len];
                    int read = 0;
                    xml = "";
                    do
                    {
                        read = stream.Read(buf, 0, len);
                        xml += Encoding.UTF8.GetString(buf, 0, read);

                    }while (read > 0);
                    stream.Close();

                    ParseRSSFeed(xml);
                }
            }
            catch (System.Security.SecurityException ex)
            {
                // Do Something
            }
 }
 
Next, you can include Linq to Xml (add System.Xml.Linq to References) to easily and quickly parse the xml to fetch the user tweets. 
You can read more about that on Scott Gu's blog post: Silverlight Tutorial Part 3: Using Networking to Retrieve Data and Populate a DataGrid
Here is, how I have done it:
The feed  you get from twitter will look like this:
<?xml version="1.0" encoding="utf-16"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Twitter / LON3WOLF</title>
        <link>http://twitter.com/LON3WOLF</link>
        <atom:link type="application/rss+xml" href="http://twitter.com/statuses/user_timeline/22100709.rss" rel="self" />
        <description>Twitter updates from Sanil Singh Tomar / LON3WOLF.</description>
        <language>en-us</language>
        <ttl>40</ttl>
           <title>LON3WOLF: ehem... RT @Zee: awww man...RT @patrick Best toilet ever! http://twitpic.com/rcvp2 #fb</title>
        <item>
            <title>LON3WOLF: @anilbpai you mean one that looks like xkcd, if you find any tool 4 that, then please RT :)</title>
            <description>LON3WOLF: @anilbpai you mean one that looks like xkcd</description>
            <pubDate>Sat, 28 Nov 2009 16:40:22 +0000</pubDate>
            <guid>http://twitter.com/LON3WOLF/statuses/6144843401</guid>
            <link>http://twitter.com/LON3WOLF/statuses/6144843401</link>
        </item>        
        <item>
            <title>LON3WOLF: @anilbpai Go to ' Block ' button-&amp;gt; Click! Click! :)</title>
            <description>LON3WOLF: @anilbpai Go to ' Block ' button-&amp;gt; Click! Click! :)</description>
            <pubDate>Fri, 27 Nov 2009 18:38:03 +0000</pubDate>
            <guid>http://twitter.com/LON3WOLF/statuses/6119125496</guid>
            <link>http://twitter.com/LON3WOLF/statuses/6119125496</link>
        </item>
    </channel>
</rss>
You can use Linq to XML in following way:
public class item
{
        public string title;
        public string description;
        public string pubDate;
        public string guid;
        public string link;
}

public void ParseRSSFeed(string xmlContent)
 {

            XDocument rss = XDocument.Parse(xmlContent);
            
            var tweets = from feed in rss.Descendants("channel").Descendants("item")
                        select new item
                        {
                            guid = (string) feed.Element("guid"),
                            pubDate = (string)feed.Element("pubDate"),
                            title = (string)feed.Element("title"),
                            description = (string)feed.Element("description"),
                            link = (string)feed.Element("link")
                        };

            Status = new item[tweets.Count()];

            //Copy description to status
            int count = 0;
            foreach (var tweet in tweets)
            {
                Status[count] = tweet;
                count++;
            }
 }
Links:

page_white_swoosh Source Code: Download

application_link Application: Download

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.