I am trying to post multiple images to twitter using the media/upload so that I can tweet using multiple images. but unable to do. So, I get an unauthorized 401 error. I can not use any third party library
var oauth_token = "***"; //"insert here...";
var oauth_token_secret = "***"; //"insert here...";
var oauth_consumer_key = "***";// = "insert here...";
var oauth_consumer_secret = "***";// = "insert here...";
// oauth implementation details
var oauth_version = "1.0";
var oauth_signature_method = "HMAC-SHA1";
// unique request details
var oauth_nonce = Convert.ToBase64String(
new 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();
var resource_url = "https://upload.twitter.com/1.1/media/upload.json";
// create oauth signature
var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" + "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}";
var baseString = string.Format(baseFormat,
oauth_consumer_key,
oauth_nonce,
oauth_signature_method,
oauth_timestamp,
oauth_token,
oauth_version//,
//Uri.EscapeDataString(screen_name)
);
baseString = string.Concat("POST&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString));
var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
"&", Uri.EscapeDataString(oauth_token_secret));
string oauth_signature;
using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey)))
{
oauth_signature = Convert.ToBase64String(
hasher.ComputeHash(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}\"";
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)
);
// make the request
ServicePointManager.Expect100Continue = false;
byte[] bytes = File.ReadAllBytes(@"C:\Users\Public\Pictures\Sample Pictures\desert.jpg");
var postBody = "media=" + Convert.ToBase64String(bytes);
resource_url += "?" + postBody;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
request.Headers.Add("Authorization", authHeader);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
WebResponse response = request.GetResponse();
string responseData = new StreamReader(response.GetResponseStream()).ReadToEnd();
response.Close();
// return responseData;
}
catch (Exception ed)
{
}
It would be great if someone could help me with this.
Clear the Browser's Cookies and CacheIf the browser's cookies or cache is corrupt, then that may cause the media upload failed issue on Twitter as Twitter fail to authenticate the media upload by the user. In this context, clearing the browser's cookies or cache may solve the Twitter media upload problem.
To access Media Studio, go to studio.twitter.com and log in using your Twitter credentials. You can also go to Twitter.com, click on the More button within the side menu and then click on the Media Studio button. Which internet browsers are supported? Chrome, Firefox, and Microsoft Edge are fully supported.
Tap the camera icon to add a new photo or video to your Tweet. Tap the photo icon to attach an existing photo, video, or GIF. Once you have 2 or more photos selected, you can tap and hold a photo to drag and reorder before Tweeting. Tip: Read about how to include a video in your Tweet.
The minimum resolution for Twitter videos is 32 x 32 and the maximum resolution is 1920 x 1200 or 1200 x 1900. Supported formats are MP4 and MOV on the Twitter mobile apps and, on the web, MP4 with H264 format with AAC audio. The maximum file size is 512MB.
Solved the issue by using Juan María Hernández's tinytwitter class with the changes that I need
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
namespace tweetmedia.Models
{
public class OAuthInfo
{
public string ConsumerKey { get; set; }
public string ConsumerSecret { get; set; }
public string AccessToken { get; set; }
public string AccessSecret { get; set; }
}
public class Tweet
{
public long Id { get; set; }
public DateTime CreatedAt { get; set; }
public string UserName { get; set; }
public string ScreenName { get; set; }
public string Text { get; set; }
}
public class TinyTwitter
{
private readonly OAuthInfo oauth;
public TinyTwitter(OAuthInfo oauth)
{
this.oauth = oauth;
}
public string UpdateStatus(string message)
{
string web = new RequestBuilder(oauth, "POST", "https://api.twitter.com/1.1/statuses/update.json")
.AddParameter("status", message)
.Execute();
return web;
}
public string UpdateStatuswithmedia(string message, string media)
{
string web = new RequestBuilder(oauth, "POST", "https://api.twitter.com/1.1/statuses/update.json")
.AddParameter("status", message)
.AddParameter("media_ids", media)
.Execute();
return web;
}
public string UpdateMedia(string message)
{
string web = new RequestBuilder(oauth, "POST", "https://upload.twitter.com/1.1/media/upload.json")
.AddParameter("media", message)
.Execute();
return web;
}
public IEnumerable<Tweet> GetHomeTimeline(long? sinceId = null, int? count = 20)
{
return GetTimeline("https://api.twitter.com/1.1/statuses/home_timeline.json", sinceId, count);
}
public IEnumerable<Tweet> GetMentions(long? sinceId = null, int? count = 20)
{
return GetTimeline("https://api.twitter.com/1.1/statuses/mentions.json", sinceId, count);
}
public IEnumerable<Tweet> GetUserTimeline(long? sinceId = null, int? count = 20)
{
return GetTimeline("https://api.twitter.com/1.1/statuses/user_timeline.json", sinceId, count);
}
private IEnumerable<Tweet> GetTimeline(string url, long? sinceId, int? count)
{
var builder = new RequestBuilder(oauth, "GET", url);
if (sinceId.HasValue)
builder.AddParameter("since_id", sinceId.Value.ToString());
if (count.HasValue)
builder.AddParameter("count", count.Value.ToString());
string content;
var response = builder.Execute(out content);
var serializer = new JavaScriptSerializer();
var tweets = (object[])serializer.DeserializeObject(content);
return tweets.Cast<Dictionary<string, object>>().Select(tweet =>
{
var user = ((Dictionary<string, object>)tweet["user"]);
var date = DateTime.ParseExact(tweet["created_at"].ToString(),
"ddd MMM dd HH:mm:ss zz00 yyyy",
CultureInfo.InvariantCulture).ToLocalTime();
return new Tweet
{
Id = (long)tweet["id"],
CreatedAt =
date,
Text = (string)tweet["text"],
UserName = (string)user["name"],
ScreenName = (string)user["screen_name"]
};
}).ToArray();
}
#region RequestBuilder
public class RequestBuilder
{
private const string VERSION = "1.0";
private const string SIGNATURE_METHOD = "HMAC-SHA1";
private readonly OAuthInfo oauth;
private readonly string method;
private readonly IDictionary<string, string> customParameters;
private readonly string url;
public RequestBuilder(OAuthInfo oauth, string method, string url)
{
this.oauth = oauth;
this.method = method;
this.url = url;
customParameters = new Dictionary<string, string>();
}
public RequestBuilder AddParameter(string name, string value)
{
customParameters.Add(name, value.EscapeUriDataStringRfc3986());
return this;
}
public string Execute()
{
string content;
Execute(out content);
return content;
}
public WebResponse Execute(out string content)
{
try
{
var timespan = GetTimestamp();
var nonce = CreateNonce();
var parameters = new Dictionary<string, string>(customParameters);
AddOAuthParameters(parameters, timespan, nonce);
var signature = GenerateSignature(parameters);
var headerValue = GenerateAuthorizationHeaderValue(parameters, signature);
var request = (HttpWebRequest)WebRequest.Create(GetRequestUrl());
request.Method = method;
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add("Authorization", headerValue);
WriteRequestBody(request);
// It looks like a bug in HttpWebRequest. It throws random TimeoutExceptions
// after some requests. Abort the request seems to work. More info:
// http://stackoverflow.com/questions/2252762/getrequeststream-throws-timeout-exception-randomly
var response = request.GetResponse();
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
content = reader.ReadToEnd();
}
}
request.Abort();
return response;
}
catch (Exception ex)
{
content = "";
return null;
}
}
private void WriteRequestBody(HttpWebRequest request)
{
if (method == "GET")
return;
var requestBody = Encoding.ASCII.GetBytes(GetCustomParametersString());
using (var stream = request.GetRequestStream())
stream.Write(requestBody, 0, requestBody.Length);
}
private string GetRequestUrl()
{
if (method != "GET" || customParameters.Count == 0)
return url;
return string.Format("{0}?{1}", url, GetCustomParametersString());
}
private string GetCustomParametersString()
{
return customParameters.Select(x => string.Format("{0}={1}", x.Key, x.Value)).Join("&");
}
private string GenerateAuthorizationHeaderValue(IEnumerable<KeyValuePair<string, string>> parameters, string signature)
{
return new StringBuilder("OAuth ")
.Append(parameters.Concat(new KeyValuePair<string, string>("oauth_signature", signature))
.Where(x => x.Key.StartsWith("oauth_"))
.Select(x => string.Format("{0}=\"{1}\"", x.Key, x.Value.EscapeUriDataStringRfc3986()))
.Join(","))
.ToString();
}
private string GenerateSignature(IEnumerable<KeyValuePair<string, string>> parameters)
{
var dataToSign = new StringBuilder()
.Append(method).Append("&")
.Append(url.EscapeUriDataStringRfc3986()).Append("&")
.Append(parameters
.OrderBy(x => x.Key)
.Select(x => string.Format("{0}={1}", x.Key, x.Value))
.Join("&")
.EscapeUriDataStringRfc3986());
var signatureKey = string.Format("{0}&{1}", oauth.ConsumerSecret.EscapeUriDataStringRfc3986(), oauth.AccessSecret.EscapeUriDataStringRfc3986());
var sha1 = new HMACSHA1(Encoding.ASCII.GetBytes(signatureKey));
var signatureBytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(dataToSign.ToString()));
return Convert.ToBase64String(signatureBytes);
}
private void AddOAuthParameters(IDictionary<string, string> parameters, string timestamp, string nonce)
{
parameters.Add("oauth_version", VERSION);
parameters.Add("oauth_consumer_key", oauth.ConsumerKey);
parameters.Add("oauth_nonce", nonce);
parameters.Add("oauth_signature_method", SIGNATURE_METHOD);
parameters.Add("oauth_timestamp", timestamp);
parameters.Add("oauth_token", oauth.AccessToken);
}
private static string GetTimestamp()
{
return ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
}
private static string CreateNonce()
{
return new Random().Next(0x0000000, 0x7fffffff).ToString("X8");
}
}
#endregion
}
public static class TinyTwitterHelperExtensions
{
public static string Join<T>(this IEnumerable<T> items, string separator)
{
return string.Join(separator, items.ToArray());
}
public static IEnumerable<T> Concat<T>(this IEnumerable<T> items, T value)
{
return items.Concat(new[] { value });
}
public static string EncodeRFC3986(this string value)
{
// From Twitterizer http://www.twitterizer.net/
if (string.IsNullOrEmpty(value))
return string.Empty;
var encoded = Uri.EscapeDataString(value);
return Regex
.Replace(encoded, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper())
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("$", "%24")
.Replace("!", "%21")
.Replace("*", "%2A")
.Replace("'", "%27")
.Replace("%7E", "~");
}
public static string EscapeUriDataStringRfc3986(this string value)
{
StringBuilder escaped = new StringBuilder();
string validChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";
foreach (char c in value)
{
if (validChars.Contains(c.ToString()))
{
escaped.Append(c);
}
else
{
escaped.Append("%" + Convert.ToByte(c).ToString("x2").ToUpper());
}
}
// Return the fully-RFC3986-escaped string.
return escaped.ToString();
}
}
}
I am using this method to upload the image with post
public string PostToTwitter(string PostData, string SelectedMedia)
{
string tweetresp = "";
DataSet ds = new DataSet();
try
{
var oauth = new OAuthInfo
{
AccessToken = Convert.ToString(Session["twitter_token"]),
AccessSecret = Convert.ToString(Session["twitter_token_secret"]),
ConsumerKey = Convert.ToString(ConfigurationSettings.AppSettings["TwitterConsumerKey"]) ,
ConsumerSecret =Convert.ToString(ConfigurationSettings.AppSettings["TwitterConsumerSecret"])
};
var twitter = new TinyTwitter(oauth);
List<string> li = new List<string>();
string[] files = SelectedMedia.Split(',');
List<string> FileList = new List<string>();
string media = "";
if (!string.IsNullOrEmpty(SelectedMedia))
{
foreach (string file in files)
FileList.Add(Server.MapPath(file));
foreach (string item in FileList)
{
li.Add(GetMediaId(twitter, item));
}
media = string.Join(",", li);
}
//li.Add(GetMediaId(twitter, file1));
if (!string.IsNullOrEmpty(SelectedMedia))
{
tweetresp = twitter.UpdateStatuswithmedia(PostData, media);
}
else
tweetresp = twitter.UpdateStatus(PostData);
}
catch (Exception ex)
{
}
return tweetresp;
}
Here is the GetMediaId method
public string GetMediaId(TinyTwitter twit, string file)
{
byte[] files = System.IO.File.ReadAllBytes(file);
string Base64File = Convert.ToBase64String(files);
string response = twit.UpdateMedia(Base64File);
JObject j = JObject.Parse(response);
return Convert.ToString(j["media_id"]);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With