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
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:
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.