Loading a Twitter Feed in WinRT

June 17, 2014

Recently, Twitter in their wisdom, discontinued the support for atom feed.  I have a couple of programs that were interrogating this, and they all suddenly (and gracefully I might add) stopped working.

The changeover is not that straightforward, especially if you don’t want to use third party libraries.

Introduction and Caveat

What I’m trying to achieve with this post is to collate all the information that I’ve gathered into a single place, so that switching from the old atom Twitter search:


string atomTweetSearchURL = string.Format("http://search.twitter.com/search.atom?q={0}", searchText);

…to the new OAuth2 can be achieved without looking anywhere else.

This is based on a Windows Store app.  There are some features that will be specific to a Store App, but I have no reason to believe this wouldn’t be generally applicable (and possible in a similar fashion) outside of the RT environment.  Having said that, there are other resources more applicable if you have access to the full .NET framework.

Finally, I have made use of lots of internet help. Where possible, I’ll link the appropriate articles, but if I forget to, just assume that the code you see here was either directly taken, or adapted from something I found online.

A last point, if you use libraries such as Linq to Twitter and JSON.NET, you’ll make your life easier; personally, I wanted to do this without a third party library.

Twitter Configuration

Previously, the URL above would allow you to simply interrogate the Twitter stream and Twitter didn’t need to know about who you were. That is now replaced. You don’t necessarily need to log-in as a user, you can use Application Only Identification. To set this up, visit https://apps.twitter.com/app/new

twitterappdetails

Only the first three boxes are required information. If you are developing a Windows 8 App then the Website can be a deep link to your application; for example, mine was here:

http://apps.microsoft.com/windows/app/geegeeeight/26d0e292-ca89-4ad6-bddc-cde3f2f9e7eb

Once you click on the button to create a new app:

CreateTwitterApp

You will be provided with a Key and a Secret. These are long strings of numbers and letters that will identify your app.

JSON Helpers

We’ll be dealing in JSON. As such, you need to be able to serialise and de-serialise JSON data. The first thing to do is to create a helper class such as follows:


    class JSonSerialiserHelper
    {

        public static T Deserialize(string json)
        {
            var \_Bytes = Encoding.Unicode.GetBytes(json);
            using (MemoryStream \_Stream = new MemoryStream(\_Bytes))
            {
                var \_Serializer = new DataContractJsonSerializer(typeof(T));
                return (T)\_Serializer.ReadObject(\_Stream);
            }
        }

        public static string Serialize(object instance)
        {
            using (MemoryStream \_Stream = new MemoryStream())
            {
                var \_Serializer = new DataContractJsonSerializer(instance.GetType());
                \_Serializer.WriteObject(\_Stream, instance);
                \_Stream.Position = 0;
                using (StreamReader \_Reader = new StreamReader(\_Stream)) 
                { return \_Reader.ReadToEnd(); }
            }
        }
    }

You’ll also need to deal with dates, so add this, too:


        internal static DateTime ConvertDate(string dateIn)
        {
            // http://blog.kevinyu.org/2012/07/handling-json-in-net.html
            const string Const\_TwitterDateTemplate = "ddd MMM dd HH:mm:ss +ffff yyyy";
            DateTime createdAt = DateTime.ParseExact(dateIn, Const\_TwitterDateTemplate, new System.Globalization.CultureInfo("en-GB"));

            return createdAt;
        }

Obviously if you’re not in Britain you may wish to change the culture.

Get a Token

There is now a two step authentication; it works like this: 1. Send your application details (key and secret) to Twitter and get an Authorisation Token 2. Use the token to search Twitter with your criteria

The Key and Secret are what you obtained above when you registered your app; the code below should get you a token with that information:


        // http://stackoverflow.com/questions/22733283/twitter-oauth2-using-winrt
        private async Task TwitterOAuth(string key, string secret)
        {
            var client = new HttpClient();
            var uri = new Uri("https://api.twitter.com/oauth2/token");

            var encodedConsumerKey = WebUtility.UrlEncode(key);
            var encodedConsumerSecret = WebUtility.UrlEncode(secret);
            var combinedKeys = String.Format("{0}:{1}", encodedConsumerKey, encodedConsumerSecret);
            
            var utfBytes = System.Text.Encoding.UTF8.GetBytes(combinedKeys);
            var encodedString = Convert.ToBase64String(utfBytes);

            client.DefaultRequestHeaders.Add("Authorization", string.Format("Basic {0}", encodedString));

            var data = new List\> 
            { 
                new KeyValuePair("grant\_type", "client\_credentials") 
            };

            var postData = new FormUrlEncodedContent(data);

            var response = await client.PostAsync(uri, postData);
            TwitAuthenticateResponse authenticationResponse;
            using (response)
            {
                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception("Error.  Authentication Failed.");

                var content = await response.Content.ReadAsStringAsync();
                authenticationResponse = JSonSerialiserHelper.Deserialize(content);
                if (authenticationResponse.token\_type != "bearer")
                    throw new Exception("Wrong result type.  Authentication failed.");

                return authenticationResponse;
            }            
        }

TwitAuthenticateResponse looks like this:


    public class TwitAuthenticateResponse
    {
        public string token\_type { get; set; }
        public string access\_token { get; set; }        
    }

If you call that, you should have a valid token:


var auth = await TwitterOAuth("key", "secret");

Now the search

Now you have the authentication, you can use that to call the search; here’s the code:


        // http://stackoverflow.com/questions/23671600/using-a-token-to-search-on-twitter-with-oauth2
        private async Task SearchTwitter(string accessToken, string srchStr)
        {
            var client = new HttpClient();
            var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
            var uri = new Uri(searchUrl);

            client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", accessToken));

            HttpResponseMessage response = await client.GetAsync(uri);
            string content = await response.Content.ReadAsStringAsync();

            return content;
        }

And here’s the call:


string srch = await SearchTwitter(auth.access\_token, searchText);

What to do with the results?

Okay - you can use JSON.NET as mentioned before; however, here’s a way to do it without.

First, you need to declare some classes to hold the data:


    public class TwitSearchResult
    {
        public StatusClass[] statuses { get; set; }

    }

    public class TwitUser
    {
        public string ScreenName { get; set; }
    }

    public class StatusClass
    {
        public string text { get; set; }
        public string source { get; set; }
        public TwitUser user { get; set; }
        public string created\_at { get; set; }
    }

Finally, use the helper classes above to deserialise what you get back:


            TwitSearchResult srchResult = JSonSerialiserHelper.Deserialize(srch);

Summary

The final top level call now looks like this:


            var auth = await TwitterOAuth("key", "secret");
            string srch = await SearchTwitter(auth.access\_token, searchText);

            TwitSearchResult srchResult = JSonSerialiserHelper.Deserialize(srch);

Conclusion

Like I said before, if I’ve used your code and not credited you then it’s not intentional. My aim was just to get all this into a single place for future reference. If you’d like me to reference anything that isn’t referenced then contact me or leave a message.



Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2024