Tweet feeds using API not fetching on Mac OS + Firefox combination

dotnet
oauth
api
csharp

#1

I am fetching recent Tweets from one channel and showing them on webpage using https://api.twitter.com/1.1/statuses/user_timeline.json. This is working fine on most of browsers and devices. But for ‘mac OS + Mozilla Firefox’ combination, it consistently fails.

Is there any browser support issue of API JSON for this combination? Any special treatment required in code for this situation?


#2

Hard to tell - are you able to show the code you’re using? Are you doing this directly from Javascript in the browser? What is failing, what is the error code?


#3

We are using C# code for passing values (screen name & counts) to handler file (.ashx) whose response is appended in HTML (.aspx) file. Most of the times the response fails, is it something with our code OR with API JSON?

We have replaced Screen name and other authentication info with ‘****’ in below code.

Here is source file code:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.Globalization;
using System.Collections;
using System.Text.RegularExpressions;

public partial class Philanthropies_Default : System.Web.UI.Page
{
    string twString = "";
    string path = "";
    protected void Page_Load(object sender, EventArgs e)
    {
        #region Twitter API call
        path = "****://www.*****.com/";
        path += "TwitterAPI_1_1.ashx?screen_name=******&count=5";
        try
        {
            using (WebClient tw = new WebClient())
            {
                tw.Headers.Add("HeaderID", "*****");
                twString = tw.DownloadString(path);
            }
        }
        catch { }
        // grid1.InnerHtml += twString;
        Int32 tweetCount = 1;
        Regex linkParser = new Regex(@"((?:<li>.*?<\/li>){1})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        string rawString = twString;
        try { 
            if (rawString != "" && rawString != null && rawString != String.Empty)
            {
				foreach (Match m in linkParser.Matches(rawString))
				{
					Regex linkdiv = new Regex(@"((?:<div class='twtBox'>.*?<\/div>){1})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
					String divValue = "";
					foreach (Match j in linkdiv.Matches(m.Value))
					{
						divValue = j.Value;
					}
					switch (tweetCount)
					{
						case 1:
							tweet1.InnerHtml = divValue;
							break;
						case 2:
							tweet2.InnerHtml = divValue;
							break;
						case 3:
							tweet3.InnerHtml = divValue;
							break;
					}
					tweetCount += 1;
				}
			}else
            {
                owl_slider.Visible = false;
            }
		}catch (NullReferenceException ex)
        {
            // but that's ok, we can handle it now
            owl_slider.Visible = false;
        }
        #endregion Twitter API call ends
    }
}

Here is the handler file

<%@ WebHandler Language="C#" Class="TwitterAPI_1_1" %>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using System.IO;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
public class TwitterAPI_1_1 : IHttpHandler
{
    string cachedTweets = "";
    string tweets = "";
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        if (context.Request.Headers["HeaderID"] != null && context.Server.HtmlEncode(context.Request.Headers["HeaderID"]) == "************************")
        {
            if (context.Request.QueryString["screen_name"] != null && context.Request.QueryString["count"] != null)
            {
                string screen_name = context.Server.HtmlEncode(context.Request.QueryString["screen_name"]);
                string count = context.Server.HtmlEncode(context.Request.QueryString["count"]);
                #region Caching the response object


                if (context.Cache["Responsefeed"] == null)
                {
                    cachedTweets = TwitterHelper.TwitterCallGet(
                        "https://api.twitter.com/1.1/statuses/user_timeline.json",
                        new KeyValuePair<string, string>[] {
                    new KeyValuePair<String, String>("screen_name","*******"),
                    new KeyValuePair<String, String>("count", count)
            });
                    context.Cache.Add("Responsefeed", cachedTweets, null, DateTime.Now.AddSeconds(900), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
                }
                else
                {
                    cachedTweets = (string)context.Cache["Responsefeed"];
                    if (cachedTweets == null || cachedTweets.Length == 0)
                    {
                        cachedTweets = TwitterHelper.TwitterCallGet(
                        "https://api.twitter.com/1.1/statuses/user_timeline.json",
                        new KeyValuePair<string, string>[] {
                    new KeyValuePair<String, String>("screen_name","***********"),
                    new KeyValuePair<String, String>("count", "3")
            });
                        context.Cache["Responsefeed"] = cachedTweets;
                    }
                }
                #endregion
            }
        }
        List<Tweets> ValuesCollection = new List<Tweets>();
        ValuesCollection = new JavaScriptSerializer().Deserialize<List<Tweets>>(cachedTweets);

        List<Tweets> finalList = ValuesCollection.Where(x => x.in_reply_to_screen_name == null && x.in_reply_to_status_id == null && x.in_reply_to_status_id_str == null && x.in_reply_to_user_id == null && x.in_reply_to_user_id_str == null && x.retweeted == false).Select(x => x).ToList();
      
        try
        {
            for (int i = 0; i < 4; i++)
            {
		string pattern = @"([ ](http|https)[ ]) |([ ](http|https)$)|([ ](http:|https:)$)|([ ](http:/|https:/)$)|([ ](http://|https://)$)";
		string cleanString = string.Empty;
                string tweetText = string.Empty;
		 string stripped = string.Empty;
                tweetText = finalList[i].text;
                if (!string.IsNullOrEmpty(tweetText))
                {
                    byte[] bytes = Encoding.Default.GetBytes(tweetText);
                    String myString = Encoding.UTF8.GetString(bytes);
                    stripped = Regex.Replace(myString, "[^ -~]", "");
		    cleanString = Regex.Replace(stripped, pattern, string.Empty);
                    String WithUrl = ConvertUrl(cleanString);

                    var date = DateTime.ParseExact(finalList[i].created_at, "ddd MMM dd HH:mm:ss +0000 yyyy", System.Globalization.CultureInfo.InvariantCulture).ToString("MMMM dd, yyyy");
                    tweets += "<li><div class='twtBox'><p>" + WithUrl + "</p><p>" + date + "</p></div></li>";
                }
            }
        }
        catch { }

        context.Response.Write(tweets);
    }

    public String ConvertUrl(String txt)
    {

        Regex linkParser = new Regex(@"https://t.[0-9a-zA-Z-._~:/?#]*", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        string rawString = txt;
        string test = string.Empty, test1 = string.Empty, test2 = string.Empty;
        foreach (Match m in linkParser.Matches(rawString))
        {
            test = "";//removing twitter image;
            rawString = rawString.Replace(m.Value.ToString(), test);
        }
        Regex tweetHash = new Regex(@"(#\w+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        foreach (Match m in tweetHash.Matches(rawString))
        {
            test1 = "<a target='_blank' href='https://twitter.com/hashtag/" + m.Value.TrimStart('#') + "?src=hash' >" + m.Value + "</a>";
            rawString = rawString.Replace(m.Value.ToString(), test1);
        }
        Regex tweetAt = new Regex(@"(@\w+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        foreach (Match m in tweetAt.Matches(rawString))
        {
		 if (!m.Value.Contains("@SeattleChildren"))
           	{
            test2 = "<a target='_blank' href='https://twitter.com/" + m.Value.TrimStart('@') + "' >" + m.Value + "</a>";
            rawString = rawString.Replace(m.Value.ToString(), test2);
		}
        }
	if (rawString.Contains("@SeattleChildren"))
        {
            rawString = rawString.Replace("@SeattleChildren", "<a style='color:008272;' target='_blank' href='https://twitter.com/SeattleChildren' >@SeattleChildren</a>");
        }

        return rawString;
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}

public class Tweets
{
    public string text { get; set; }
    public string created_at { get; set; }
    public bool retweeted { get; set; }
    public bool favorited { get; set; }
    public string id_str { get; set; }
    public string in_reply_to_status_id { get; set; }
    public string in_reply_to_status_id_str { get; set; }
    public string in_reply_to_user_id { get; set; }
    public string in_reply_to_user_id_str { get; set; }
    public string in_reply_to_screen_name { get; set; }
}
public static class TwitterHelper
{
    private static string TwitterCall(string Method, string ResourceUrl, IEnumerable<KeyValuePair<string, string>> RequestParameters)
    {
        // oauth application keys
        var oauth_token = "XXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_token_secret = "XXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_consumer_key = "XXXXXXXXXXXXXXXXXXXXXXXXX";
        var oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXX";

        // oauth implementation details
        var oauth_version = "1.0";
        var oauth_signature_method = "HMAC-SHA1";

        // unique request details
        var oauth_nonce = Convert.ToBase64String(
            new System.Text.ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
        var timeSpan = DateTime.UtcNow
            - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();

        //setup the parameters that we will be putting in the authorization
        var authorizationParameters = new List<KeyValuePair<string, string>>() { 
                new KeyValuePair<string, string>("oauth_consumer_key",oauth_consumer_key),
                new KeyValuePair<string, string>("oauth_nonce",oauth_nonce),
                new KeyValuePair<string, string>("oauth_signature_method",oauth_signature_method),
                new KeyValuePair<string, string>("oauth_timestamp",oauth_timestamp),
                new KeyValuePair<string, string>("oauth_token",oauth_token),
                new KeyValuePair<string, string>("oauth_version",oauth_version)
            };

        //combine and sort all parameters as per //dev.twitter.com/docs/auth/creating-signature
        var allParameters = authorizationParameters.Union(RequestParameters).OrderBy(tmp => tmp.Key);

        //put all paramneters into a & delimited string and make sure our values are % escaped        
        var baseString = string.Join("&", allParameters.Select(p => string.Format("{0}={1}", p.Key, Uri.EscapeDataString(p.Value))).ToArray());

        //finish the base string
        baseString = string.Format("{0}&{1}&{2}", Method, Uri.EscapeDataString(ResourceUrl), Uri.EscapeDataString(baseString));

        var compositeKey = string.Format("{0}&{1}", Uri.EscapeDataString(oauth_consumer_secret), Uri.EscapeDataString(oauth_token_secret));

        //use our composite key to get the auth signature
        string oauth_signature = null;
        using (System.Security.Cryptography.HMACSHA1 hasher = new System.Security.Cryptography.HMACSHA1(System.Text.ASCIIEncoding.ASCII.GetBytes(compositeKey)))
        {
            oauth_signature = Convert.ToBase64String(
                hasher.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(baseString)));
        }

        // create the request header
        var headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
                           "oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
                           "oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
                           "oauth_version=\"{6}\"";

        //get the actual string version of the auth header and its values
        var authHeader = string.Format(headerFormat,
                                Uri.EscapeDataString(oauth_nonce),
                                Uri.EscapeDataString(oauth_signature_method),
                                Uri.EscapeDataString(oauth_timestamp),
                                Uri.EscapeDataString(oauth_consumer_key),
                                Uri.EscapeDataString(oauth_token),
                                Uri.EscapeDataString(oauth_signature),
                                Uri.EscapeDataString(oauth_version)
                        );

        System.Net.ServicePointManager.Expect100Continue = false;

        //add our query string parameters to our url
        var parameterString = string.Join("&", RequestParameters.Select(p => string.Format("{0}={1}", p.Key, Uri.EscapeDataString(p.Value))).ToArray());
        ResourceUrl += "?" + parameterString;


        //create our request
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(ResourceUrl);

        //set our info
        request.Headers.Add("Authorization", authHeader);
        request.Method = Method;
        request.ContentType = "application/x-www-form-urlencoded";

        //get the response and return the result from the stream
        using (var response = (System.Net.HttpWebResponse)request.GetResponse())
        {
            using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
            {
                return reader.ReadToEnd();
            }
        }
    }

    public static string TwitterCallGet(string ResourceUrl, IEnumerable<KeyValuePair<string, string>> RequestParameters)
    {
        return TwitterCall("GET", ResourceUrl, RequestParameters);
    }

    public static string TwitterCallPost(string ResourceUrl, IEnumerable<KeyValuePair<string, string>> RequestParameters)
    {
        return TwitterCall("POST", ResourceUrl, RequestParameters);
    }
}

#4

OK, so this is only failing on Mac OS X with Firefox, and it works in all other browser combinations?

If this is browser specific it implies that either Firefox isn’t executing your HTML+JS the same way as other browsers, or that the request from Firefox is interpreted differently on the server side?

What errors are you seeing / how is it failing? Are you seeing errors on the server-side, or in Firefox console? Are you able to trace out the JSON response on the server or client side, so that you can compare the difference between results on Firefox and other browsers?

(I’d also point out that there are a bunch of libraries like LinqToTwitter, Tweetinvi etc which handle all of the OAuth stuff for you, and would save you having to manually build the request string yourself)


#5

As mentioned by @andypiper if the problem is client side specific then just check that the information you receive are correct on your server side.


#6

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.