Using OAuth to Send Updates to Twitter Using C#

Well I'm not sure if it's better. To be honest it's a bit more difficult to set up initially but it's a bit more secure than the way I showed before. Anyway, this year (in fact early this year), Twitter started a transition to using OAuth. Since I'm new to messing with the service, I had no idea. But then again I'm pretty oblivious to most things, so I might have missed that information even if I had been an early adopter. That being said, I've talked about OAuth before and I'll assume that you've read the post here. If not take a look before looking at the code below. Anyway, enough stalling, let's jump into some code:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/


#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utilities.Web.OAuth;
using System.Text.RegularExpressions;
using System.Web;
#endregion

namespace Utilities.Web.Twitter
{
    /// <summary>
    /// Helper class to deal with Twitter
    /// </summary>
    public class Twitter:OAuth.OAuth
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public Twitter()
            : base()
        {
            this.SignatureType = Signature.HMACSHA1;
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Gets a request token/token secret
        /// </summary>
        /// <param name="Token">The request token</param>
        /// <param name="TokenSecret">The request token secret</param>
        public void GetRequestToken(out string Token,out string TokenSecret)
        {
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri("http://twitter.com/oauth/request_token");
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            string Value = RestHelper.GET();
            Regex TokenRegex = new Regex("oauth_token=(?<Value>[^&]*)");
            Match TempToken = TokenRegex.Match(Value);
            Token = TempToken.Groups["Value"].Value;
            Regex TokenSecretRegex = new Regex("oauth_token_secret=(?<Value>[^&]*)");
            Match TempTokenSecret = TokenSecretRegex.Match(Value);
            TokenSecret = TempTokenSecret.Groups["Value"].Value;
        }

        /// <summary>
        /// Gets the location of the authorization site (requires
        /// request token/token secret)
        /// </summary>
        /// <returns>The location that the user must go in order to
        /// authorize the app and get the authorization PIN</returns>
        public string GetAuthorizationSite()
        {
            this.Method = HTTPMethod.GET;
            this.Url = new Uri("http://twitter.com/oauth/authorize");
            this.AddParameter("oauth_callback", "oob");
            return new Uri(GenerateRequest()).ToString();
        }

        /// <summary>
        /// Gets the access token/token secret which are used in actual calls
        /// (requires the PIN from the authorization site and the request token
        /// and request token secret)
        /// </summary>
        /// <param name="PIN">PIN received from the authorization site</param>
        /// <param name="AccessToken">The access token</param>
        /// <param name="AccessTokenSecret">The access token secret</param>
        public void GetAccessToken(string PIN, out string AccessToken, out string AccessTokenSecret)
        {
            this.Url = new Uri("http://twitter.com/oauth/access_token");
            this.AddParameter("oauth_verifier", PIN);
            this.Method = HTTPMethod.POST;
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            string Value = RestHelper.POST();
            Regex TokenRegex = new Regex("oauth_token=(?<Value>[^&]*)");
            Match TempToken = TokenRegex.Match(Value);
            AccessToken = TempToken.Groups["Value"].Value;
            Regex TokenSecretRegex = new Regex("oauth_token_secret=(?<Value>[^&]*)");
            Match TempTokenSecret = TokenSecretRegex.Match(Value);
            AccessTokenSecret = TempTokenSecret.Groups["Value"].Value;
        }

        /// <summary>
        /// Updates the status of the user
        /// </summary>
        /// <param name="Status">Status of the user (needs to be within 140 characters)</param>
        /// <returns>The XML doc returned from the Twitter service</returns>
        public string UpdateStatus(string Status)
        {
            this.Method = HTTPMethod.POST;
            this.Url = new Uri("http://twitter.com/statuses/update.xml");
            this.AddParameter("status", Status);
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            return RestHelper.POST();
        }

        /// <summary>
        /// Gets a user's timeline from the Twitter service
        /// </summary>
        /// <param name="UserName">The screen name of the user</param>
        /// <returns>The XML doc returned from the Twitter service
        /// contatining the timeline</returns>
        public string GetTimeline(string UserName)
        {
            this.Method = HTTPMethod.POST;
            this.Url = new Uri("http://twitter.com/statuses/user_timeline.xml");
            this.AddParameter("screen_name", UserName);
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            return RestHelper.GET();
        }

        #endregion
    }
}

The code above uses the OAuth helper class (modified, from the post that I link to so go to the svn store on codeplex to see the latest version) along with a new REST helper class that I created to work with Twitter. But before I show the REST class, I should explain the code above. There are a number of functions here that you need to call prior to ever being able to send anything to Twitter. The first is GetRequestToken. This does what it sounds like. It gets a request token from the Twitter service. The request token is then used to register an app with a user. Prior to authorizing the app, you can't do a damn thing when using OAuth. The request token/token secret that is returned by the Twitter service are then used in the GetAuthorizationSite function. This function simply gets you the location that the user must go in order to authorize your app to work with their account. The user goes to that location, clicks on Allow and is then given a PIN number. Note that during all of this you have to hold onto the request token/secret token so that you can use them along with the PIN in the next function: GetAccessToken. This function actually trades in the request token that you're using for an access token/token secret. These are then used in all of the functions that actually do anything...

That's right, you just went through three steps just so you can start to use the service. It's annoying but on the bright side, it's much more secure. Not to mention it tends to make those who are paranoid trust you a bit more as they are no longer giving you their user name and password. Anyway, the other two functions in the class do two things. The first is a status update function. It's basically what I showed you before in the previous post but cleaned up and using OAuth instead of basic authentication. The second function allows you to query Twitter for a timeline of a single user. It returns an XML file that you'll need to parse, but it does get the job done for now. They should be fairly simple to follow... Well, they would be if I had shown you the REST class before now. So you're not completely confused here it is:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/


#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
#endregion

namespace Utilities.Web.REST
{
    /// <summary>
    /// Class designed to help with calling REST based applications
    /// </summary>
    public class REST
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public REST()
        {
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Does a GET to the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string GET()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "GET";
                Request.ContentType = "text/xml";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a POST to the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string POST()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "POST";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a DELETE on the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string DELETE()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "DELETE";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a PUT on the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string PUT()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "PUT";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// Sets up any data that needs to be sent
        /// </summary>
        /// <param name="Request">The web request object</param>
        private void SetupData(HttpWebRequest Request)
        {
            if (string.IsNullOrEmpty(Data))
            {
                Request.ContentLength = 0;
                return;
            }
            try
            {
                byte[] ByteData = UTF8Encoding.UTF8.GetBytes(Data);
                Request.ContentLength = ByteData.Length;
                using (Stream RequestStream = Request.GetRequestStream())
                {
                    RequestStream.Write(ByteData, 0, ByteData.Length);
                }
            }
            catch { throw; }
        }

        /// <summary>
        /// Sets up any credentials (basic authentication,
        /// for OAuth, please use the OAuth class to create the
        /// URL)
        /// </summary>
        /// <param name="Request">The web request object</param>
        private void SetupCredentials(HttpWebRequest Request)
        {
            try
            {
                if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password))
                {
                    Request.Credentials = new NetworkCredential(UserName, Password);
                }
            }
            catch { throw; }
        }

        /// <summary>
        /// Sends the request to the URL specified
        /// </summary>
        /// <param name="Request">The web request object</param>
        /// <returns>The string returned by the service</returns>
        private string SendRequest(HttpWebRequest Request)
        {
            try
            {
                using (HttpWebResponse Response = Request.GetResponse() as HttpWebResponse)
                {
                    if (Response.StatusCode != HttpStatusCode.OK)
                        throw new Exception("The request did not complete successfully and returned status code " + Response.StatusCode);
                    using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                    {
                        return Reader.ReadToEnd();
                    }
                }
            }
            catch { throw; }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// URL to send the request to
        /// </summary>
        public Uri Url { get; set; }

        /// <summary>
        /// Any data that needs to be appended to the request
        /// </summary>
        public string Data { get; set; }

        /// <summary>
        /// User name (basic authentication)
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// Password (basic authentication)
        /// </summary>
        public string Password { get; set; }

        #endregion
    }
}

If you've ever dealt with a REST API before, it's pretty basic. But more or less it's divided into four functions, GET, PUT, POST, DELETE. It also allows for basic authentication if you need it. But basically you just load up the URL, any data that needs to be appended, user name and password and call the appropriate function. It in turn returns anything that the server sends back. So there you go, basic REST helper and Twitter helper classes. It's not that difficult to build off of them, so take a look, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 12/9/2009 at 10:11 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Posting to Twitter Using C#

Twitter for me is something that I get really little value out of. Sure there are some decent links thrown out on there but I usually see the same things on the various blogs that I follow. Not to mention, I don't care what anyone else is doing at any given time. At the same time I've been told multiple times by my friends in marketing that it's a great tool that I can use to do, well, something. I usually stop listening before they finish the sentence. But I am a fan of new tools so I figured I might as well learn how to use it.

There are a ton of already made wrappers for the Twitter API and in fact I use one here on the site (although modified slightly). However I was curious how it all worked and decided to write some code which I figured I might as well share with you:

    public static class Twitter
    {
        public static string Post(string Status, string UserName, string Password)
        {
            string URL = "http://twitter.com/statuses/update.xml";
            string Data = "status=" + HttpUtility.UrlEncode(Status);

            HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);
            if (!(string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password)))
            {
                Request.Credentials = new NetworkCredential(UserName, Password);
                Request.ContentType = "application/x-www-form-urlencoded";
                Request.Method = "POST";
                Request.ServicePoint.Expect100Continue = false;
                byte[] Bytes = Encoding.UTF8.GetBytes(Data);

                Request.ContentLength = Bytes.Length;
                using (Stream RequestStream = Request.GetRequestStream())
                {
                    RequestStream.Write(Bytes, 0, Bytes.Length);
                    using (WebResponse Response = Request.GetResponse())
                    {
                        using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                        {
                            return Reader.ReadToEnd();
                        }
                    }
                }
            }
            return "";
        }
    }

The code above does a simple status update. It turns out that Twitter uses a simple REST API. As such you'll notice that the code sets up an url with the status information, sets up a web request, and sends it off (returning the response to the user which is an xml document). It's pretty simple really but there is one item that threw me off. You'll notice that there is a line that has Expect100Continue=false. It turns out that Twitter does not like the 100-Continue header. In fact if you send that header it will instantly throw out whatever you send it. I have no idea why. I'm certain that there is a reason, I just don't know what it is. Anyway, by setting that to false you can get around that issue. Other than that, it's pretty simple. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 11/19/2009 at 8:36 AM
Tags: ,
Categories: C#
Post Information: Permalink | Comments (4) | Post RSSRSS comment feed