I'm using V2 of the Etsy Api. I know my consumer key and build up of my token is all fine because when I make a request for listings related to a receipt, I receive all details:
$"https://openapi.etsy.com/v2/receipts/{receipt.receipt_id}/listings?";
I then try to obtain all transactions for a listing:
$"https://openapi.etsy.com/v2/listings/{lineItem.listing_id}/transactions?";
this call never returns and it doesn't error. As far as I can tell, I've built the call correctly.
After the build up of the call which includes all the OAUth stuff, If I paste the whole url directly in a browser, data is sent back to the browser.
So this is the build up of the call to Etsy:
I have a generic method
public async Task<T> MakeGetCallToEtsy<T>(string requestUrl)
{
var client = new OAuthRequest
{
Method = "GET",
Type = OAuthRequestType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ConsumerKey = _consumerKey,
ConsumerSecret = _consumerSecret,
Token = _token,
TokenSecret = _tokenSeret,
RequestUrl = requestUrl
};
var url = requestUrl + client.GetAuthorizationQuery();
var result = await url.GetStringAsync();
return JsonConvert.DeserializeObject<T>(result);
}
And this is my call to the method:
string requestUrl = $"https://openapi.etsy.com/v2/listings/{lineItem.listing_id}/transactions?";
var transactions = await _etsyComms.MakeGetCallToEtsy<EtsyTransaction>(requestUrl);
I thought the issue might be with the deserialization, but placing a breakpoint there, again it never gets to that point.
Has anybody come across this issue before, or can see anything I've missed in my build up to the call.
Related
I am trying to get Autherization Token for TD Ameritrade API using C# .NET. First I get a "CODE" following some steps. Then I use that code in Postman, send the request I get Authorization Code back.
Here is my C# .NET Code to do the same :- (the "CODE" is one time value, can't be re-use. I get a NEW CODE and use that in C# app)
public async Task SignIn(string consumerKey, string code, string redirectUrl = "https://127.0.0.1:4000/TDCallBack/SetCode?code")
{
var path = "https://api.tdameritrade.com/v1/oauth2/token";
using (var client = new HttpClient())
{
var dict = new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "access_type", "offline" },
{ "client_id", $"{consumerKey}" },
{ "redirect_uri", redirectUrl },
{ "code", code }
};
var req = new HttpRequestMessage(HttpMethod.Post, path) { Content = new FormUrlEncodedContent(dict) };
var res = await client.SendAsync(req);
}
}
But I get "Invalid_Grant" as return, which means API call went to TD Ameritrate server but it did not return the Authorization Token. It could be header/data issue, but no explanation why it did not return an Authorization token.
I think it is a C# programming issue, because TD Ameritrade has a WEB Page (like swagger) to submit API Calls. Exact same API call work with same parameters/values (of course NEW CODE every time). Postman works, TD Ameritrade Website Works BUT my C# Code doesn't work. I will appreciate if I can get some light on this problem. Thanks.
Have you tried using a proxy (like Fiddler) to see what the differences are between the Postman request and request from your code?
That should go a long way towards finding obvious differences. It also looks like you’re not setting the content type to be x-www-form-urlencoded which may be necessary for the endpoint to properly handle the request.
See also: How to POST using HTTPclient content type = application/x-www-form-urlencoded
When I post to my API (written in .NET core and hosted on Linux) from Postman, everything works as expected. When I do the same from code (using HttpClient), the parameters do not get sent. Below my code:
var content = new FormUrlEncodedContent(new []
{
new KeyValuePair<string, string>(nameof(userName), userName),
new KeyValuePair<string, string>(nameof(serialNumber), serialNumber)
});
var result = await _httpClient.PostAsync(_uri, content).ConfigureAwait(false);
var json = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<Response>(json);
In my opinion content should get sent and everything should be alright. I see significant differences between the calls in Wireshark.
Working POST from Postman:
POST from HttpClient that does not work:
.
What can I do to make sure that my HttpClient.PostAsync sends the data correctly?
The Postman version doesn't have a body, but it has userName and serialNumber encoded into the url as query parameters.
In order to achieve the same using HttpClient, you need to add those parameters to the url.
var uriBuilder = new UriBuilder(_uri);
// If you already have query parameters, this code will preserve them.
// Otherwise you can just create a new NameValueCollection instance.
var parameters = HttpUtility.ParseQueryString(uriBuilder.Query);
parameters[nameof(userName)] = userName;
parameters[nameof(serialNumber)] = serialNumber;
uriBuilder.Query = parameters.ToString();
// Pass null as HttpContent to make HttpClient send an empty body
var result = await _httpClient.PostAsync(uriBuilder.ToString(), null).ConfigureAwait(false);
I'm stumped here and hoping for some help. I'll paste in the relevant section of the Getflix API (https://getflix.zendesk.com/hc/en-gb/articles/201689644-API-Resource-Regions):
POST v1/regions.json
Updates the region for a specified service. Only 1 service can be updated at a time, and the following JSON object must be present in the POST body.
{"service": < serviceName >,"region": < regionCode >}
serviceName: is a valid service name (see region list below)
regionCode: is the ISO 2 letter country code for the region to switch to (in upper-case).
Example Usage
curl -u <api_key>:x -X POST -d '{"service":"netflix","region":"US"}' https://www.getflix.com.au/api/v1/regions.json
And here is my code:
string response = await theHandler.POSTreq("https://www.getflix.com.au/api/v1/regions/list.json", "{\"service\":\"netflix\",\"region\":\"US\"}");
and here is theHandler.POSTreq:
public async Task<string> POSTreq(string requestURL, string sendJson)
{
//set credentials
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials = new NetworkCredential(apiKey, "x");
Uri requestUri = new Uri(requestURL);
var objClint = new HttpClient(handler);
HttpResponseMessage respon = await objClint.PostAsync(requestUri, new StringContent(sendJson, System.Text.Encoding.UTF8, "application/json"));
string responJsonText = await respon.Content.ReadAsStringAsync();
return responJsonText;
}
As far as I can figure out, this SHOULD work. it doesn't. The response text I end up getting isn't an error but a whole bunch of HTML.
Anyone know what I'm doing wrong? I've spent hours on this and I'm stumped. ha
Yes, I'm an idiot. I was using the wrong URL. lol.
I am working with OAuth at the moment. The problem with the current code is it doesn't wait until the user allows the application on the site and gets the proper key and secret. I was using a threading type wait but, sometimes it not long enough...some users are slower then others. I have attached a snippet of my code. What I would like to know is where to insert a while statement, or should I even use that ?
public OAuthToken GetRequestToken(Uri baseUri, string consumerKey, string consumerSecret)
{
var uri = new Uri(baseUri, "oauth/request_token");
uri = SignRequest(uri, consumerKey, consumerSecret);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
var response = request.GetResponse();
var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);
return new OAuthToken(token, secret);
}
You should switch over to the newer System.Net.Http and System.Net.Http.WebRequest libraries that come with .NET now. These all use the new async programming stuff that is available with .NET 4.5.
You can call a request (returning you a task object that you can wait on) and automatically pause the thread for the response. The UI won't respond, as normal. That is probably the easiest thing to do if you don't understand how the new async and await keywords work. For more information on them, see http://msdn.microsoft.com/en-us/library/hh191443.aspx
Here is your code doing things with the new libraries:
using System.Net.Http;
public OAuthToken GetRequestToken(Uri baseUri, string consumerKey, string consumerSecret)
{
var uri = new Uri(baseUri, "oauth/request_token");
uri = SignRequest(uri, consumerKey, consumerSecret);
var message = new HttpRequestMessage(new HttpMethod("GET"), uri);
var handler = new WebRequestHandler();
var client = new HttpClient(handler);
// Use the http client to send the request to the server.
Task<HttpResponseMessage> responseTask = client.SendAsync(message);
// The responseTask object is like a wrapper for the other task thread.
// We can tell this task object that we want to pause our current thread
// and wait for the client.SendAsync call to finish.
responseTask.Wait();
// - Once that thread finishes, and the code continues on, we need to
// tell it to read out the response data from the backing objects.
// - The responseTask.Result property represents the object the async task
// was wrapping, we want to pull it out, then use it and get the content
// (body of the response) back.
// - Getting the response actually creates another async task (the
// .ReadAsStringAsync() call) but by accessing the .Result
// property, it is as if we called .ReadAsStringAsync().Wait(); Except that
// by using Result directly, we not only call Wait() but we get the resulting,
// wrapped object back. Hope that didn't confuse you much :)
var queryString = responseTask.Result.Content.ReadAsStringAsync().Result;
// And all your other normal code continues.
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);
return new OAuthToken(token, secret);
}
Why Not use a modal pop up and then call the authentication class on the submit button
I have searched high and low for an answer to this problem. Basically, I am creating a C# application which (In it's first incarnation) will authenticate with the Projectplace API which uses OAuth 1.0a. It currently returns the oauth_verifier to the address bar, but when I use the var response = request.GetResponse(); method, it returns the oauth_token and oauth token_secret which I sent as part of the authorization in the first place.
Perhaps I am misunderstanding the way this process is supposed to work, but I've read every single answer out there and none seem to address this question. Do you have to, or is it possible, to pull the verifier code from the address bar (or wherever else it can be obtained), after I have entered my username and password on the authentication page after callback URL is loaded?
I believe OAuth1.0a requires the verification code to retrieve an access token, and I cannot find a simple way to pull the verification code.
I would really appreciate any help, it's driving me nuts!!
UPDATED 03.12.12
Thanks for your response!
Essentially, I am the client attempting to retrieve the oauth_verifier from the oauth provider after sending this initial request below, my next step is to authorize then retrieve verifier. I tried the following, hopefully as you suggested, like swimming in the deep end here :)
//Generate string for initiation request.
requestUri.AppendFormat("?oauth_consumer_key={0}&", consumerKey);
requestUri.AppendFormat("oauth_nonce={0}&", nonce);
requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
requestUri.AppendFormat("oauth_version={0}&", "1.0");
requestUri.AppendFormat("oauth_signature={0}", signature);
var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
request.Method = WebRequestMethods.Http.Get;
var response = request.GetResponse();
var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var tokenSecret = parts[0].Substring(parts[0].IndexOf('=') + 1);
var queryString2 = String.Format("oauth_token={0}", token);
//AUTHORIZE WITH CREDENTIALS FROM USER.
var authorizeUrl = "https://api.projectplace.com/authorize?" + queryString;
Process.Start(authorizeUrl);`
//TRY AND READ VERIFICATION STRING AFTER AUTHORIZATION REDIRECT`
String oauthVerifier = HttpContext.Current.Request.QueryString["oauth_verifier"];
Unfortunately, once i've done this, I can't seem to get a querystring returned showing the oauth_verifier that I am clearly seeing in the string showing in the address bar. (Yes it's a very newbish way of describing it, i'm learning the code as well as OAuth :P).
Thanks for your help so far. I tried to run the above, but it just said that says "Object reference not set to an instance of an object.".
Also, if I attempt to use the previous code I used to obtain the querystring / response? from the initiation request using the following lines, the querystring3 just comes back as blank... really frustrating! :)
var queryString3 = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts3 = queryString3.Split('&');
I'm going to assume that by "in the address bar" you mean that the oauth_verifier is passed to your site from the ProjectPlace server via a query string parameter in the redirect URL. In order to read this in your C# server side code, you would use something like the following (I modified your sample code for this solution):
requestUri.AppendFormat("?oauth_consumer_key={0}&", consumerKey);
requestUri.AppendFormat("oauth_nonce={0}&", nonce);
requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
requestUri.AppendFormat("oauth_version={0}&", "1.0");
requestUri.AppendFormat("oauth_signature={0}", signature);
var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
//Note: this is unnecessary - GET is the default
request.Method = WebRequestMethods.Http.Get;
//By casting to HttpWebResponse you get access to the QueryString property
var response = request.GetResponse() as HttpWebResponse;
var oauthVerifier = response.QueryString["oauth_verifier"];
//The response stream contains the HTTP response body,
//which will not contain the URL to which the redirect is sent
//I'm not sure if there is anything there that you will need
var responseBody = new StreamReader(response.GetResponseStream()).ReadToEnd();
//AUTHORIZE WITH CREDENTIALS FROM USER. -- Not sure what this section is doing
var queryString = string.Format("oauth_token={0}", oauthVerifier);
var authorizeUrl = "https://api.projectplace.com/authorize?" + queryString;
Process.Start(authorizeUrl);