c# Unable to parse xml, receiving error 463 - c#

Basically I am trying to parse xml from this However I recieve {"The remote server returned an error: (463)."} (System.Net.WebException) The error happens in string xml = webClient2.DownloadString(address);
Here is my full code
Task.Run((Action)(() =>
{
XmlDocument xmlDocument = new XmlDocument();
using (WebClient webClient1 = new WebClient())
{
WebClient webClient2 = webClient1;
Uri address = new Uri("https://habbo.com/gamedata/furnidata_xml/1");
string xml = webClient2.DownloadString(address);
xmlDocument.LoadXml(xml);
}
foreach (XmlNode xmlNode1 in xmlDocument.GetElementsByTagName("furnitype"))
{
string nr1 = "[" + xmlNode1.Attributes["id"].Value + "]";
string nr2 = " : " + xmlNode1.Attributes["classname"].InnerText;
foreach (XmlNode xmlNode2 in xmlNode1)
{
XmlNode childNode = xmlNode2;
if (childNode.Name == "name")
{
this.FurniCB.Invoke((Action)(() => this.FurniCB.Items.Add((object)(nr1 + nr2 + " : " + childNode.InnerText))));
this.FurniDataList.Add(nr1 + nr2 + " : " + childNode.InnerText);
}
}
}
}));
Thanks in advance

I tested your code's downloading part. All you need is to add User-Agent header to the request..
webClient1.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");

Related

Foreach result in textbox

please view the code provided by Microsoft below:
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Microsoft.Translator.Samples
{
class TranslateArraySample
{
public static async Task Run(string authToken)
{
var from = "en";
var to = "es";
var translateArraySourceTexts = new []
{
"The answer lies in machine translation.",
"the best machine translation technology cannot always provide translations tailored to a site or users like a human ",
"Simply copy and paste a code snippet anywhere "
};
var uri = "https://api.microsofttranslator.com/v2/Http.svc/TranslateArray";
var body = "<TranslateArrayRequest>" +
"<AppId />" +
"<From>{0}</From>" +
"<Options>" +
" <Category xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" />" +
"<ContentType xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\">{1}</ContentType>" +
"<ReservedFlags xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" />" +
"<State xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" />" +
"<Uri xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" />" +
"<User xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" />" +
"</Options>" +
"<Texts>" +
"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">{2}</string>" +
"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">{3}</string>" +
"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">{4}</string>" +
"</Texts>" +
"<To>{5}</To>" +
"</TranslateArrayRequest>";
string requestBody = string.Format(body, from, "text/plain", translateArraySourceTexts[0], translateArraySourceTexts[1], translateArraySourceTexts[2], to);
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(uri);
request.Content = new StringContent(requestBody, Encoding.UTF8, "text/xml");
request.Headers.Add("Authorization", authToken);
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
switch (response.StatusCode)
{
case HttpStatusCode.OK:
Console.WriteLine("Request status is OK. Result of translate array method is:");
var doc = XDocument.Parse(responseBody);
var ns = XNamespace.Get("http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2");
var sourceTextCounter = 0;
foreach (XElement xe in doc.Descendants(ns + "TranslateArrayResponse"))
{
foreach (var node in xe.Elements(ns + "TranslatedText"))
{
**Console.WriteLine("\n\nSource text: {0}\nTranslated Text: {1}", translateArraySourceTexts[sourceTextCounter], node.Value);**
}
sourceTextCounter++;
}
break;
default:
Console.WriteLine("Request status code is: {0}.", response.StatusCode);
Console.WriteLine("Request error message: {0}.", responseBody);
break;
}
}
}
}
}
Please look at the ** line, node.value is the result I want. According to the code, we will have 3 sentences translated from the string array above. However, I want it to display in a textbox. let say I have a textbox with ID = textbox.
I have tried using this :
foreach (var node in xe.Elements(ns + "TranslatedText"))
{
textbox.Text=node.value;
}
sourceTextCounter++;
However, the result only for the last sentence.
Please share your thought how to do it!
Try this:
foreach (var node in xe.Elements(ns + "TranslatedText"))
{
textbox.Text += node.value + " ";
}
Because you're always overwriting .Text you need to concatenate with something like:
textbox.Text += node.value + Environment.NewLine;
This would add your node.value and a newline character for each node found.
EDIT: Also want to state that Environment.NewLine is ignored if the Multiline property of the textbox is false.

Screen Scraping - By pass Captcha Validation by code [ traffic issue ]

I am doing one screen scraping project in asp.net using c#, And I can scrap the screen successfully.
But I have to make one by one multiple requests to the targeted server, but after some time server redirects to Captcha validation page, at that time I stuck.
Here is my code :
public static string SearchPage(Uri url, int timeOutSeconds)
{
StringBuilder sb = new StringBuilder();
try
{
string place = HttpUtility.ParseQueryString(url.Query).Get("destination").Split(':')[1];
string resultID = HttpUtility.ParseQueryString(url.Query).Get("resultID");
string checkin = HttpUtility.ParseQueryString(url.Query).Get("checkin").Replace("-", "");
string checkout = HttpUtility.ParseQueryString(url.Query).Get("checkout").Replace("-", "");
string Rooms = HttpUtility.ParseQueryString(url.Query).Get("Rooms");
string adults_1 = HttpUtility.ParseQueryString(url.Query).Get("adults_1");
string languageCode = "EN";
string currencyCode = "INR";
string ck = "languageCode=" + languageCode + "; a_aid=400; GcRan=1; __RequestVerificationToken=IHZjc7KM_LbUXRypz02LoK4wmeLNcmRpIr-6vmPl5eNepILScAc15vn0TgQJtmABgedDy8xz4bnkqC30_zUGE1A1SaA1; Analytics=LandingID=place:77469:0m&LanguageCode=" + languageCode + "&WebPageID=9; Tests=165F000901000A1100F81000FE110100000102100103100104000105100052; dcid=dal05; currencyCode=" + currencyCode + "; countryCode=" + languageCode + "; search=place:" + place + "#" + checkin + "#" + checkout + "#" + adults_1 + "; SearchHistory=" + place + "%" + checkin + "%" + checkout + "%" + adults_1 + "%" + currencyCode + "%%11#" + place + "%" + checkin + "%" + checkout + "%" + adults_1 + "%" + currencyCode + "%%" + resultID + "#; visit=date=2015-11-23T18:26:05.4922127+11:00&id=45111733-acef-47d1-aed3-63cef1a60591; visitor=id=efff4190-a4a0-41b5-b807-5d18e4ee6177&tracked=true";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = timeOutSeconds * 1000;
request.ReadWriteTimeout = timeOutSeconds * 1000;
request.KeepAlive = true;
request.Method = "GET";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36 OPR/33.0.1990.115";
request.Headers.Add("Accept-Language", "en-US,en;q=0.8");
request.Headers.Add("Cookie", ck);
request.Headers.Add("Upgrade-Insecure-Requests", "1");
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream());
string line = reader.ReadToEnd();
sb.Append(line);
sb.Replace("<br/>", Environment.NewLine);
sb.Replace("\n", Environment.NewLine);
sb.Replace("\t", " ");
reader.Close();
reader.Dispose();
request.Abort();
}
catch (Exception ex)
{
//throw ex;
}
return sb.ToString();
}
This code works successfully but after some requests it stuck because may be server allows some limited requests.

web client PUT method in MVC

I am trying to do PUT method for API service
Here is the code:
WebClient box = new WebClient();
var uuid = "40922d72-57dd-4fa6-bd64-f406f444dbb6";
if (HttpContext.Current.Session["JSESSIONCOOKIE"] != null)
{
}
else
{
return null;
}
box.Headers["Cookie"] = HttpContext.Current.Session["JSESSIONCOOKIE"].ToString();
string sampleJson = "{" + "autoPresetTimes" + ":" + "{" + "0" + ":" + "Night" + "}}".ToString();
string json = new JavaScriptSerializer().Serialize(sampleJson);
Uri uri = new Uri("https://my.zipato.com:443/zipato-web/v2/thermostats/" + uuid + "/config");
box.UploadString(uri, "PUT", json);
My problem is that this above gives me error 500 from server. I think because i dont send my body like this:
{"autoPresetTimes": {
"0": "Night"
}
}
On API page it says Parameter content type: application/json so i guess i should send my response o look like this above.
Any thoughts on this?
The json that you are creating looks incorrect. You need to put your keys within double quotes.
string json =
"{" + "\"autoPresetTimes\"" + ":" + "{" + "\"0\"" + ":" + "\"Night\"" + "}}";
Uri uri =
new Uri("https://my.zipato.com:443/zipato-web/v2/thermostats/" + uuid + "/config");
box.UploadString(uri, "PUT", json);
Note: You do not need to specify port 443 in your url. The default port for https is 443

parsing an xmldocument from a webrequest

I'm having a heck of a time parsing this layout:
<string xmlns="http://www.namespaceuri.com/Admin/ws">
<CardTrxSummary>
<PaymentMethod>
<Payment_Type_ID>VISA </Payment_Type_ID>
<Authorization>0.0000</Authorization>
<Capture>0.0000</Capture> <ForceCapture>0.0000</ForceCapture>
<PostAuth>0.0000</PostAuth> <Return>0.0000</Return>
<Sale>3419.2700</Sale> <Receipt>0.0000</Receipt>
<RepeatSale>0.0000</RepeatSale>
<Activate>0.0000</Activate>
<Deactivate>0.0000</Deactivate>
<Reload>0.0000</Reload>
<Authorization_Cnt>0</Authorization_Cnt>
<Capture_Cnt>0</Capture_Cnt>
<ForceCapture_Cnt>0</ForceCapture_Cnt>
<PostAuth_Cnt>0</PostAuth_Cnt>
<Return_Cnt>0</Return_Cnt>
<Sale_Cnt>13</Sale_Cnt>
<Receipt_Cnt>0</Receipt_Cnt>
<RepeatSale_Cnt>0</RepeatSale_Cnt>
<Activate_Cnt>0</Activate_Cnt>
<Deactivate_Cnt>0</Deactivate_Cnt>
<Reload_Cnt>0</Reload_Cnt>
<Cnt>13</Cnt>
</PaymentMethod>
</CardTrxSummary>
</string>
I am trying with this code to get the a specific result:
private static string ReadValueFromXml(XmlDocument xmlDocument, string field)
{
var xdoc = xmlDocument.ToXDocument();
var ns = "http://www.namespaceuri.com/Admin/ws";
return xdoc.Descendants(ns + "PaymentMethod")
.Select(x => (string) x.Attribute("Cnt"))
.FirstOrDefault();
}
At this point, it's giving me this message:
The ':' character, hexadecimal value 0x3A, cannot be included in a
name.
I tried it this way:
XmlNodeList xnList = xmlDocument.SelectNodes("/CardTrxSummary/PaymentMethod");
foreach (XmlNode xn in xnList)
{
Console.WriteLine("Sale: " + xn["Sale"].InnerText);
Console.WriteLine("Sale_Cnt: " + xn["Sale_Cnt"].InnerText);
Console.WriteLine("Payment_Type_ID: " + xn["Payment_Type_ID"].InnerText);
}
And it never went inside the foreach.
How do I get the values within PaymentMethod?
EDIT
I looked at the xmldocument's innertext and this is how it's displayed:
"<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns=\"http://www.namespaceuri.com/Admin/ws\"><CardTrxSummary>\r\n <PaymentMethod>\r\n <Payment_Type_ID>VISA </Payment_Type_ID>\r\n <Authorization>0.0000</Authorization>\r\n <Capture>0.0000</Capture>\r\n <ForceCapture>0.0000</ForceCapture>\r\n <PostAuth>0.0000</PostAuth>\r\n <Return>0.0000</Return>\r\n <Sale>3419.2700</Sale>\r\n <Receipt>0.0000</Receipt>\r\n <RepeatSale>0.0000</RepeatSale>\r\n <Activate>0.0000</Activate>\r\n <Deactivate>0.0000</Deactivate>\r\n <Reload>0.0000</Reload>\r\n <Authorization_Cnt>0</Authorization_Cnt>\r\n <Capture_Cnt>0</Capture_Cnt>\r\n <ForceCapture_Cnt>0</ForceCapture_Cnt>\r\n <PostAuth_Cnt>0</PostAuth_Cnt>\r\n <Return_Cnt>0</Return_Cnt>\r\n <Sale_Cnt>13</Sale_Cnt>\r\n <Receipt_Cnt>0</Receipt_Cnt>\r\n <RepeatSale_Cnt>0</RepeatSale_Cnt>\r\n <Activate_Cnt>0</Activate_Cnt>\r\n <Deactivate_Cnt>0</Deactivate_Cnt>\r\n <Reload_Cnt>0</Reload_Cnt>\r\n <Cnt>13</Cnt>\r\n </PaymentMethod>\r\n</CardTrxSummary></string>"
Which, I assume, is part of my problem?
EDIT#2
This is what I ended up doing to get it to work. I'm sure there is a better way:
var tst2 = tst.InnerText.Replace("<", "<").Replace(">", ">").Replace("\r\n", string.Empty);
Console.WriteLine("Cnt: " + ReadXmlValue1(tst2, "Cnt"));
and my method to parse it:
private static void ReadXmlValue1(string xmlDocument)
{
XDocument xdoc = XDocument.Parse(xmlDocument);
//XNamespace ns = "http://www.namespaceuri.com/Admin/ws";
var payments = from p in xdoc.Descendants("PaymentMethod")
select new
{
Sale = (decimal)p.Element("Sale"),
SaleCount = (int)p.Element("Sale_Cnt"),
PaymentType = (string)p.Element("Payment_Type_ID")
};
Console.WriteLine("Count: " + payments.Count());
foreach (var payment in payments)
{
Console.WriteLine("Sale: " + payment.Sale);
Console.WriteLine("Sale_Cnt: " + payment.SaleCount);
Console.WriteLine("Payment_Type_ID: " + payment.PaymentType);
}
}
EDIT#3
This is how I'm creating the xmldocument:
/// <summary>
/// Get Data in xml format by url
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private static XmlDocument GetXmlDataFromUrl(string url)
{
//requesting the particular web page
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
//geting the response from the request url
var response = (HttpWebResponse)httpRequest.GetResponse();
//create a stream to hold the contents of the response (in this case it is the contents of the XML file
var receiveStream = response.GetResponseStream();
//creating XML document
var mySourceDoc = new XmlDocument();
//load the file from the stream
if (receiveStream != null)
{
mySourceDoc.Load(receiveStream);
//close the stream
receiveStream.Close();
return mySourceDoc;
}
return null;
}
You can use LINQ to XML to get list of strongly typed anonymous payment objects:
WebClient client = new WebClient();
string content = client.DownloadString(url);
XDocument xdoc = XDocument.Parse(content);
XNamespace ns = "http://www.namespaceuri.com/Admin/ws";
var payments = from p in xdoc.Descendants(ns + "PaymentMethod")
select new {
Sale = (decimal)p.Element(ns + "Sale"),
SaleCount = (int)p.Element(ns + "Sale_Cnt"),
PaymentType = (string)p.Element(ns + "Payment_Type_ID")
};
Keep in mind, that your xml has namespace declared, so you should provide it when specifying element names.
Usage:
foreach(var payment in payments)
{
Console.WriteLine("Sale: " + payment.Sale);
Console.WriteLine("Sale_Cnt: " + payment.SaleCount);
Console.WriteLine("Payment_Type_ID: " + payment.PaymentType);
}
XmlNode node = xmlDocument.SelectSingleNode("/string/CardTrxSummary/PaymentMethod");
Console.WriteLine("Sale: " + node.SelectSingleNode("Sale").InnerText);
Console.WriteLine("Sale_Cnt: " + node.SelectSingleNode("Sale_Cnt").InnerText);
Console.WriteLine("Payment_Type_ID: " + node.SelectSingleNode("Payment_Type_ID").InnerText);
or you can use getElementByTagName instead;
Console.WriteLine("Sale: " + xmlDocument.getElementByTagName("Sale").InnerText);
Console.WriteLine("Sale_Cnt: " + xmlDocument.getElementByTagName("Sale_Cnt").InnerText);
Console.WriteLine("Payment_Type_ID: " + xmlDocument.getElementByTagName("Payment_Type_ID").InnerText);
And just a note, the above 2 method is assuming that the tag will never return null.
If you want to handle possible null node, you can do something like this.
string text = xmlDocument.getElementByTagName("Sale") != null ? xmlDocument.getElementByTagName("Sale").InnerText : "unidentified";
The above line has the format like this:
var variable = condition ? A : B;
It's basically saying that if condition is true, variable equals A, otherwise variable equals B.

Twitter POST problems using api 1.1

We've just changed to Twitter api 1.1, and now Tweeting doesn't work & returns an error "The remote server returned an error: (400) Bad Request." Researching on SO about this suggests that it's something to do with authentication, but we are sending the accessToken & secret which we've just got from the login page. It all worked fine with api 1.0. The code is -
public void Tweet(Action<string> response, string message)
{
StringBuilder sb = new StringBuilder();
sb.Append("POST&");
sb.Append(Uri.EscapeDataString(_postUrl));
sb.Append("&");
string oauthNonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
string timeStamp = MakeTimestamp();
var dict = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", _oAuthConfig.ConsumerKey },
{ "oauth_nonce", oauthNonce },
{ "oauth_signature_method", "HMAC-SHA1" },
{ "oauth_timestamp", timeStamp },
{ "oauth_token", _accessToken },
{ "oauth_version", "1.0" },
};
foreach (var keyValuePair in dict)
{
sb.Append(Uri.EscapeDataString(string.Format("{0}={1}&", keyValuePair.Key, keyValuePair.Value)));
}
string encodedMessage = EscapeAdditionalChars(Uri.EscapeDataString(message));
sb.Append(Uri.EscapeDataString("status=" + encodedMessage));
string signatureBaseString = sb.ToString();
// create the signature
string signatureKey = Uri.EscapeDataString(_oAuthConfig.ConsumerSecret) + "&" + Uri.EscapeDataString(_accessTokenSecret);
var hmacsha1 = new HMACSHA1(new ASCIIEncoding().GetBytes(signatureKey));
string signatureString = Convert.ToBase64String(hmacsha1.ComputeHash(new ASCIIEncoding().GetBytes(signatureBaseString)));
// create the headers
string authorizationHeaderParams = String.Empty;
authorizationHeaderParams += "OAuth ";
authorizationHeaderParams += "oauth_consumer_key=\"" + _oAuthConfig.ConsumerKey + "\", ";
authorizationHeaderParams += "oauth_nonce=\"" + oauthNonce + "\", ";
authorizationHeaderParams += "oauth_signature=\"" + Uri.EscapeDataString(signatureString) + "\", ";
authorizationHeaderParams += "oauth_signature_method=\"" + "HMAC-SHA1" + "\", ";
authorizationHeaderParams += "oauth_timestamp=\"" + timeStamp + "\", ";
authorizationHeaderParams += "oauth_token=\"" + _accessToken + "\", ";
authorizationHeaderParams += "oauth_version=\"" + "1.0" + "\"";
string messageToPost = EscapeAdditionalChars(SpacesToPlusSigns(message));
// initialise the WebClient
WebClient client = new WebClient();
client.Headers [HttpRequestHeader.Authorization] = authorizationHeaderParams;
client.UploadDataCompleted += (s, eArgs) =>
{
if (eArgs.Error == null)
response(DefaultSuccessMessage());
else
response(eArgs.Error.Message);
};
try
{
Uri uri = new Uri(_postUrl);
try
{
client.UploadDataAsync(uri, "POST", Encoding.UTF8.GetBytes("status=" + messageToPost));
}
catch (WebException e)
{
Log.Info("TwitterService->Tweet web error: " + e.Message);
response(DefaultErrorMessage());
}
catch (Exception e)
{
// Can happen if we had already favorited this status
Log.Info("TwitterService->Tweet error: " + e.Message);
response(DefaultErrorMessage());
}
}
catch (WebException e)
{
Log.Info("TwitterService->Tweet web error 2: " + e.Message);
response(DefaultErrorMessage());
}
catch (Exception e)
{
Log.Info("TwitterService->Tweet error 2: " + e.Message);
response(DefaultErrorMessage());
}
}
Basically, I'd like to be able to Tweet without using any 3rd party libraries such as Twitterizer (even TweetStation seems to be broken with api 1.1) - surely it can't be that difficult!
Any help much appreciated, as it feels a bit like a brick wall at the moment - I'm also fairly new to c#, which doesn't help...
Edited to show code which wasn't clear previously.
Finally found the solution, as usual with most of these things, it was pretty simple. Code below -
public void Tweet(Action<string> response, string message)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat ("status={0}", PercentEncode(message));
string content = sb.ToString();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_postUrl);
request.Headers.Add("Authorization", AuthorizeRequest(_accessToken, _accessTokenSecret, "POST", new Uri(_postUrl), content));
request.ContentType = "application/x-www-form-urlencoded";
request.ServicePoint.Expect100Continue = false;
request.Method = "POST";
try
{
try
{
using (Stream stream = request.GetRequestStream())
{
Byte[] streamContent = Encoding.UTF8.GetBytes("status=" + PercentEncode(message));
stream.Write(streamContent, 0, streamContent.Length);
}
HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
string contents = "";
using (Stream stream = webResponse.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
contents = reader.ReadToEnd();
}
Console.WriteLine("Twitter response: " + contents);
response(DefaultSuccessMessage());
}
catch (WebException e)
{
Log.Info("TwitterService->Tweet web error: " + e.Message);
response(DefaultErrorMessage());
}
catch (Exception e)
{
// Can happen if we had already favorited this status
Log.Info("TwitterService->Tweet error: " + e.Message);
response(DefaultErrorMessage());
}
}
catch (WebException e)
{
Log.Info("TwitterService->Tweet web error 2: " + e.Message);
response(DefaultErrorMessage());
}
catch (Exception e)
{
Log.Info("TwitterService->Tweet error 2: " + e.Message);
response(DefaultErrorMessage());
}
}
private string AuthorizeRequest(string oauthToken, string oauthTokenSecret, string method, Uri uri, string data)
{
string oauthNonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
var headers = new Dictionary<string, string>()
{
{ "oauth_consumer_key", _oAuthConfig.ConsumerKey },
{ "oauth_nonce", oauthNonce },
{ "oauth_signature_method", "HMAC-SHA1" },
{ "oauth_timestamp", MakeTimestamp() },
{ "oauth_token", oauthToken },
{ "oauth_verifier", PercentEncode(_authorizationVerifier) },
{ "oauth_version", "1.0A" }
};
var signatureHeaders = new Dictionary<string,string>(headers);
// Add the data and URL query string to the copy of the headers for computing the signature
if (data != null && data != "")
{
var parsed = HttpUtility.ParseQueryString(data);
foreach (string k in parsed.Keys)
{
signatureHeaders.Add(k, PercentEncode(parsed [k]));
}
}
var nvc = HttpUtility.ParseQueryString(uri.Query);
foreach (string key in nvc)
{
if (key != null)
signatureHeaders.Add(key, PercentEncode(nvc [key]));
}
string signature = MakeSignature (method, uri.GetLeftPart(UriPartial.Path), signatureHeaders);
string compositeSigningKey = MakeSigningKey(_oAuthConfig.ConsumerSecret, oauthTokenSecret);
string oauth_signature = MakeOAuthSignature(compositeSigningKey, signature);
headers.Add ("oauth_signature", PercentEncode(oauth_signature));
return HeadersToOAuth(headers);
}
private static string PercentEncode (string s)
{
var sb = new StringBuilder ();
foreach (byte c in Encoding.UTF8.GetBytes (s))
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~')
sb.Append ((char) c);
else
{
sb.AppendFormat ("%{0:X2}", c);
}
}
return sb.ToString ();
}
private static string MakeTimestamp ()
{
return ((long) (DateTime.UtcNow - _unixBaseTime).TotalSeconds).ToString ();
}
private static string MakeSignature (string method, string base_uri, Dictionary<string,string> headers)
{
var items = from k in headers.Keys orderby k
select k + "%3D" + PercentEncode (headers [k]);
return method + "&" + PercentEncode (base_uri) + "&" +
string.Join ("%26", items.ToArray ());
}
private static string MakeSigningKey (string consumerSecret, string oauthTokenSecret)
{
return PercentEncode (consumerSecret) + "&" + (oauthTokenSecret != null ? PercentEncode (oauthTokenSecret) : "");
}
private static string MakeOAuthSignature (string compositeSigningKey, string signatureBase)
{
var sha1 = new HMACSHA1 (Encoding.UTF8.GetBytes (compositeSigningKey));
return Convert.ToBase64String (sha1.ComputeHash (Encoding.UTF8.GetBytes (signatureBase)));
}
private static string HeadersToOAuth (Dictionary<string,string> headers)
{
return "OAuth " + String.Join (",", (from x in headers.Keys select String.Format ("{0}=\"{1}\"", x, headers [x])).ToArray ());
}
With Twitter api 1.0, I used a WebClient to post, that doesn't work with api 1.1, and it seems that the reason for this is that you can't set the ContentType or the ServicePoint.Expect100Continue properties - without these set as I've set them, the request is sent back as (401) unauthorized. Nothing to do with encoding problems in the end.
Thanks to others for the various helper methods.
I had exactly the same problem:
This is exactly what you need to do here:
Authenticate and request a user's timeline with Twitter API 1.1 oAuth
I have created a project for this at : https://github.com/andyhutch77/oAuthTwitterTimeline
It also includes an MVC, Web app and console demo.
I ran into this problem, or at least one striking similiar (from my noob perspective), recently for an app I am building. What seemed to solve it for me (after looking at the tool at dev.twitter.com) was simply to get rid of the quotes around the parameter names, so that (in your case):
I notice that you do in fact not have quotes around your parameter names. However, it confuses me that you send authentication details twice (hence my wrongheaded post.) It works for me without doing this, and I googled it briefly and found: https://dev.twitter.com/discussions/12322#comment-27120, which confirms this can be a problem generating an Authetication Error.
400 means you are not authenticated. I recommend getting user context.
https://dev.twitter.com/docs/auth/oauth#user-context

Categories