Publish article for Apple news API using C# - (401) Unauthorized - c#

I am working on posting article using Apple news API.
I created new account and also created new channel.
Below is the code snippet which I am using.
string channel_id = "{Channel_Id}";
string api_key_id = "{Key_Id}";
string api_key_secret = "{Secret}";
var path = "https://news-api.apple.com/channels/" + channel_id + "/articles";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "multipart/form-data";
httpWebRequest.Method = "POST";
httpWebRequest.Accept = "application/json";
httpWebRequest.Host = "news-api.apple.com";
httpWebRequest.UseDefaultCredentials = true;
httpWebRequest.PreAuthenticate = true;
httpWebRequest.ProtocolVersion = HttpVersion.Version11;
httpWebRequest.KeepAlive = true;
string appleDate = String.Format("{0}Z", DateTime.UtcNow.ToString("s"));
string credentials = String.Format("{0}:{1}", "Content-Disposition", "form-data; ");
credentials += String.Format("{0}:{1}", "filename", "article.json; ");
credentials += String.Format("{0}:{1}", "name", "article.json; ");
credentials += String.Format("{0}","HHMAC; ");
credentials += String.Format("{0}={1}", "key", api_key_id + "; ");
string decodedSecret = base64Decode(api_key_secret);
string canonical_request = path + "POST" + appleDate ;
string hash = Class1.HmacSha256Digest(canonical_request, decodedSecret);
string Encodedhash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(hash));
credentials += String.Format("{0}={1}", "signature", Encodedhash + "; ");
credentials += String.Format("{0}={1}", "date", appleDate + "; ");
httpWebRequest.Headers.Add("Authorization", credentials);
using (StreamReader r = new StreamReader(Directory.GetCurrentDirectory() + ("/article.json")))
{
string json = r.ReadToEnd();
dynamic jsonObj = JsonConvert.DeserializeObject(json);
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(json);
Stream newStream = httpWebRequest.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Here is base64Decode function
public static string base64Decode(string data)
{
var base64EncodedBytes = System.Convert.FromBase64String(data);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
Here is class to convert Sha256Digest
public static class Class1
{
public static string HmacSha256Digest(this string message, string secret)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}
Whenever I am trying to post the API I am getting below error message:
"'The remote server returned an error: (401) Unauthorized".
When I am trying to post the API request using Postman then I am getting below error message:
{
"errors": [
{
"code": "WRONG_SIGNATURE"
}
]
}
Is there anything incorrect to generate Signature ?
I researched few articles but unable to find any solution.
Please guide me to find out the solution on this.

I don't have time to go through the entirety of your code and suggest you start with a simpler Channel Data request before attempting to POST json, but a potential couple of bits I noticed:
You use ASCII encoding where you should be using UTF8 throughout.
You strip hyphens from the Base64 but Apple only strips returns and
whitespace
The cannonical request should be written: "POST[url][date][contentType]" where url = "https://news-api.apple.com/channels/[channelID]/articles", date is in the format "yyyy-MM-dd'T'HH:mm:ss'Z'" and content-type = "multipart/form-data; boundary=[boundary]" where boundary is any string used to divide the content.
See also my tips on using Python, most importantly ensure you are using the path to a folder containing article.json (not the path to a file). And finally here is my own translation of the Python into Swift.

Related

Unable to Post on Pinterest using their API

I'm receiving a 400 Bad Request error message when posting a pin on Pinterest. It works using Postman, but doesn't work programmatically. Using C#, has anyone been able to successfully post a pin on Pinterest without using the pinsharp wrapper?
private void postPinterest(string messages, string id, string usertoken, string image, string boardname, string username)
{
string link = null;
boardname = boardname.Replace(" ", "-");
string board = username + "/" + boardname;
string url = "https://api.pinterest.com/v1/pins?access_token=" + usertoken;
StringBuilder sb = new StringBuilder();
if (!string.IsNullOrEmpty(board))
sb.Append("&board=" + HttpUtility.UrlEncode(board));
if (!string.IsNullOrEmpty(messages))
sb.Append("&note=" + HttpUtility.UrlEncode(messages));
if (!string.IsNullOrEmpty(link))
sb.Append("&image_url=" + HttpUtility.UrlEncode(link));
string postdata = sb.ToString().Substring(1);
PostData(url, postdata);
}
private object PostData(string url, string postdata)
{
object json=null;
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
// req.Accept = "application/json";
using (var stream = req.GetRequestStream())
{
byte[] bindata = Encoding.ASCII.GetBytes(postdata);
stream.Write(bindata, 0, bindata.Length);
}
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
string response = new StreamReader(resp.GetResponseStream()).ReadToEnd();
json = JsonConvert.DeserializeObject<dynamic>(response);
return json;
}
catch (WebException wex)
{
if (wex.Response != null)
{
using (var errorResponse = (HttpWebResponse)wex.Response)
{
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
return json;
}
}
}
}
return json;
}
EDIT:
It doesn't work using the JSON format or x-www-form-urlencoded format.
I changed the content type to application/x-www-form-urlencoded and now I'm receiving the error message below. I receive 400 Bad Request error using JSON format:
"{\n \"message\": \"405: Method Not Allowed\",\n \"type\": \"http\"\n}"
The problem is the the parameter that you are posting.
In the Api i could find board as a parameter but both note and image comes under field parameter which specifies the return type JSON.
As per documentation on this page you can post in this format
https://api.pinterest.com/v1/boards/anapinskywalker/wanderlust/pins/?
access_token=abcde&
limit=2&
fields=id,link,counts,note
So I tried the following and its getting response
https://api.pinterest.com/v1/boards/?access_token="YourTokenWithoutQuotes"&fields=id%2Ccreator
Would suggest you to first test the Api you are hitting putting a breakpoint inside the PostData function and check if the passed url is in the correct format and compare it with Pininterest API Explorer.
As you might have already received authorization code and access token so I am assuming your post function should be working fine.
public string postPinterest(string access_token,string boardname,string note,string image_url)
{
public string pinSharesEndPoint = "https://api.pinterest.com/v1/pins/?access_token={0}";
var requestUrl = String.Format(pinSharesEndPoint, accessToken);
var message = new
{
board = boardname,
note = note,
image_url = image_url
};
var requestJson = new JavaScriptSerializer().Serialize(message);
var client = new WebClient();
var requestHeaders = new NameValueCollection
{
{"Content-Type", "application/json" },
{"x-li-format", "json" }
};
client.Headers.Add(requestHeaders);
var responseJson = client.UploadString(requestUrl, "POST", requestJson);
var response = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(responseJson);
return response;
}

Ivona Request Signing Issue - signature does not match (AWS Signature Version 4)

I am trying to implement Ivona request signing based on this documnent
Everything works good and all the results match to the example value, except Signature result. So my result for the signature is cf1141e33a8fbba23913f8f36f29faa524a57db37690a1b819f43bbeaabf3b76 but in the document it is equal to 2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc
Is it my mistake or a mistake in the Ivona document?
Below is the C# code I am using:
class Program
{
static void Main()
{
try
{
Console.WriteLine(SendIvonaRequest());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static string SendIvonaRequest()
{
var date = new DateTime(2013, 09, 13, 09, 20, 54, DateTimeKind.Utc);
const string algorithm = "AWS4-HMAC-SHA256";
const string regionName = "eu-west-1";
const string serviceName = "tts";
const string method = "POST";
const string canonicalUri = "/CreateSpeech";
const string canonicalQueryString = "";
const string contentType = "application/json";
const string accessKey = "MyAccessKey";
const string secretKey = "MySecretKey";
const string host = serviceName + "." + regionName + ".ivonacloud.com";
const string requestPayload = "{\"Input\":{\"Data\":\"Hello world\"}}";
var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));
Debug.Assert(hashedRequestPayload.Equals("f43e25253839f2c3feae433c5e477d79f7dfafdc0e4af19a952adb44a60265ba"));
var dateStamp = date.ToString("yyyyMMdd");
var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);
var headers = new SortedDictionary<string, string>
{
{"content-type", "application/json"},
{"host", "tts.eu-west-1.ivonacloud.com"},
{"x-amz-content-sha256", hashedRequestPayload},
{"x-amz-date", requestDate}
};
string canonicalHeaders =
string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
const string signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
// Task 1: Create a Canonical Request For Signature Version 4
var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
'\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;
var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
Debug.Assert(hashedCanonicalRequest.Equals("73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));
// Task 2: Create a String to Sign for Signature Version 4
// StringToSign = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest
var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
hashedCanonicalRequest);
Debug.Assert(stringToSign.Equals("AWS4-HMAC-SHA256" + "\n" +
"20130913T092054Z" + "\n" +
"20130913/eu-west-1/tts/aws4_request" + "\n" +
"73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));
// Task 3: Calculate the AWS Signature Version 4
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, regionName, serviceName);
// signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
var signature = HexEncode(HmacSha256(stringToSign, signingKey));
Debug.Assert(signature.Equals("2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc"));
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
var authorization =
string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
algorithm, accessKey, dateStamp, regionName, serviceName, signedHeaders, signature);
// Send the request
var webRequest = WebRequest.Create("https://" + host + canonicalUri);
webRequest.Method = method;
webRequest.Timeout = 2000;
webRequest.ContentType = contentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
webRequest.ContentLength = requestPayload.Length;
using (Stream newStream = webRequest.GetRequestStream())
{
newStream.Write(ToBytes(requestPayload), 0, requestPayload.Length);
}
var response = (HttpWebResponse) webRequest.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (var streamReader = new StreamReader(responseStream))
{
return streamReader.ReadToEnd();
}
}
}
return string.Empty;
}
private static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
byte[] kRegion = HmacSha256(regionName, kDate);
byte[] kService = HmacSha256(serviceName, kRegion);
return HmacSha256("aws4_request", kService);
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
private static byte[] Hash(byte[] bytes)
{
var sha256 = SHA256.Create();
return sha256.ComputeHash(bytes);
}
private static byte[] HmacSha256(String data, byte[] key)
{
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
}
UPD1:
I have also tried the examples from http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html and noticed that my code generate the same signature as in those examples. So I am assuming that there is an issue in Ivona document...
UPD2:
Everything works fine! I have implemented CreateSpeech method according to the description and uploaded a full example of the usage to GitHub
https://github.com/MalyutinS/DotNetIvonaAPI
Solved! Actually there is an issue in documentation example. So the code works fine.
It's a bit old now, but it may be relevant to others using this code;
The code works fine as long as you only stick to ASCII-characters. For languages other than english, you must first convert the string to a UTF-8 byte array. That array may be longer than the number of characters in the string, consequently the length of the byte array sent through the WebRequest must reflect the length of the array itself, and not the character count.
Really a classic, but relevant to point out anyway..
This error results in the signature not being correct, hence an authentication error. The reason may not be obvious to everyone.
So the existing code;
webRequest.Method = method;
webRequest.Timeout = 2000;
webRequest.ContentType = contentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
webRequest.ContentLength = requestPayload.Length;
using (Stream newStream = webRequest.GetRequestStream())
{
newStream.Write(ToBytes(requestPayload), 0, requestPayload.Length);
}
Becomes:
var bytes = ToBytes(requestPayload);
webRequest.Method = method;
webRequest.Timeout = 2000;
webRequest.ContentType = contentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
webRequest.ContentLength = bytes.Length;
using (Stream newStream = webRequest.GetRequestStream())
{
newStream.Write(bytes, 0, bytes.Length);
newStream.Flush();
}
Also; for a more proper and reusable way of doing AWS-4 signatures, see Amazons own: http://aws.amazon.com/code

verifying iOS in app purchase receipt with C#

I am verifying my ios in app purchase receipt on my server using C# web service
I got receipt as string by doing below in Xcode:
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier];
NSLog(#"%#",receiptString);
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0];
}
and I am sending that string(receipt) to my C# web service as parameter.
Here is my web service method:
[WebMethod(Description = "Purchase Item Verify")]
public string PurchaseItem(string receiptData)
{
string returnmessage = "";
try
{
var json = "{ 'receipt-data': '" + receiptData + "'}";
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = Encoding.UTF8.GetBytes(json);
HttpWebRequest request;
request = WebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
Stream postStream = request.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Close();
var sendresponse = (HttpWebResponse)request.GetResponse();
string sendresponsetext = "";
using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
{
sendresponsetext = streamReader.ReadToEnd();
}
returnmessage = sendresponsetext;
}
catch (Exception ex)
{
ex.Message.ToString();
}
return returnmessage;
}
It always return {"status":21002}.
I have been searching for two days , but still can't find out the solution. Can someone help me, what am i wrong ?
**I am testing on sandbox that is why i use sandbox URL. I can verify the transaction receipt within my app.
I got solution
The final code that works for me is:
public string PurchaseItem(string receiptData)
{
string returnmessage = "";
try
{
// var json = "{ 'receipt-data': '" + receiptData + "'}";
var json = new JObject(new JProperty("receipt-data", receiptData)).ToString();
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = Encoding.UTF8.GetBytes(json);
// HttpWebRequest request;
var request = System.Net.HttpWebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
//Stream postStream = request.GetRequestStream();
//postStream.Write(postBytes, 0, postBytes.Length);
//postStream.Close();
using (var stream = request.GetRequestStream())
{
stream.Write(postBytes, 0, postBytes.Length);
stream.Flush();
}
// var sendresponse = (HttpWebResponse)request.GetResponse();
var sendresponse = request.GetResponse();
string sendresponsetext = "";
using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
{
sendresponsetext = streamReader.ReadToEnd().Trim();
}
returnmessage = sendresponsetext;
}
catch (Exception ex)
{
ex.Message.ToString();
}
return returnmessage;
Spending two and half days just to change a method. Thanks GOD.
Here's an alternative asynchronous implementation using HTTPClient:
public static async Task<string> CheckReceiptWithAppStore()
{
string responseStr = null;
string uri = "https://sandbox.itunes.apple.com/verifyReceipt";
string receiptData = // Get your receipt from wherever you store it
var json = new JObject(new JProperty("receipt-data", receiptData),
new JProperty("password", "paste-your-shared-secret-here")).ToString();
using (var httpClient = new HttpClient())
{
if (receiptData != null)
{
HttpContent content = new StringContent(json);
try
{
Task<HttpResponseMessage> getResponse = httpClient.PostAsync(uri, content);
HttpResponseMessage response = await getResponse;
responseStr = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
Console.WriteLine("Error verifying receipt: " + e.Message);
}
}
}
return responseStr;
}
The shared secret is not required for non-subscription based purchases.
For managing subscriptions, #Jerry Naing's answer also requires the provision of your shared secret (can be retrieved/generated from iTunes Connect). Easiest way to include this is just to add an additional property in the line defining the json var.
var json = new JObject(new JProperty("receipt-data", receiptData), new JProperty("password", "put_your_shared_secret_here")).ToString();
Failing to provide the shared secret will result in a 21004 status response.
This code example was also helpful to me and may help others: For C# developers there is a useful open-source project called APNS-Sharp which includes receipt verification code that works in ASP.NET. In particular, the Receipt.cs and ReceiptVerification.cs files in the Jdsoft.Apple.AppStore directory
Found it from this page about Xamarin: inapp purcasing ios Transactions and Verification

Send C# array to PHP web service using post

I am trying to send this array string[] str = { "abc" , "sdfsdf" }; value to PHP (web service) using the code below but it is always giving me the following output
In the PHP file I have the following code which actually receives the array and output the total structure with values:
<?php
$messages = $_POST['messages'];
print_r($messages);
?>
Probably the problem is PHP is unable to read the array I am sending; may be because I am sending it from C#.
Could you please tell me how to send the array properly so that the PHP web service can read this.
FYI: I don't have the authority to edit any code in the web service end.
My Full C# Code
string[] str = { "num" , "Hello World" };
string url = "http://localhost/a/cash.php";
HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create( url );
ASCIIEncoding encoding = new ASCIIEncoding();
string postData ;//= "keyword=moneky";
postData = "&messages[]=" + str;
byte[] data = encoding.GetBytes(postData);
httpWReq.Method = "POST";
httpWReq.ContentType = "application/x-www-form-urlencoded";
httpWReq.ContentLength = data.Length;
using (Stream stream = httpWReq.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
MessageBox.Show(responseString);
I have finally found the right solution myself after lots of trial and error. Here's the code in case if somebody needs:
I had to use dictionary:
Dictionary<string, string> myarray =
new Dictionary<string, string>();
myarray .Add("0", "Number1");
myarray .Add("1", "Hello World");
And then
string str = string.Join(Environment.NewLine, myarray);
Then my rest of the codes :
string url = "http://localhost/a/cash.php";
HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create( url );
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = "keyword=moneky";
postData += "&messages[]=" + str;
byte[] data = encoding.GetBytes(postData);
httpWReq.Method = "POST";
httpWReq.ContentType = "application/x-www-form-urlencoded";
httpWReq.ContentLength = data.Length;
using (Stream stream = httpWReq.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
MessageBox.Show(responseString);
Edit your C# code:
Old code
string postData ;//= "keyword=moneky";
postData = "&messages[]=" + str;
New code
string postData = "";
foreach (string oneString in str) {
postData += "messages[]=" + oneString + "&";
}
While the op's answer works, I found the resulting string not so well formed (I really didn't like that Environment.NewLine), so for anyone out there still trying to figure out this, the following piece of code will do the trick for any amount of postData parameters, even if some of those parameters are arrays or lists, :
string[] str = { "abc" , "sdfsdf" }
var postData = new Dictionary<string, object>()
{
{ "keyword", "monkey" },
{ "messages", str}
};
// Serialize the postData dictionary into a string
string serializedPostData = string.Empty;
foreach (KeyValuePair<string, object> pair in postData)
{
if (IsCollection(pair.Value))
{
foreach (object item in (IEnumerable)pair.Value)
{
//%5B%5D is encoding for []
serializedPostData += Uri.EscapeDataString(pair.Key) + "%5B%5D=" + Uri.EscapeDataString(Convert.ToString(item)) + "&";
}
}
else if (IsDate(pair.Value))
{
serializedPostData += Uri.EscapeDataString(pair.Key) + "=" +
Uri.EscapeDataString(((DateTime)pair.Value).ToString("o")) + "&";
}
else
{
serializedPostData += Uri.EscapeDataString(pair.Key) + "=" +
Uri.EscapeDataString(Convert.ToString(pair.Value)) + "&";
}
}
serializedPostData = serializedPostData.TrimEnd('&');
byte[] data = Encoding.ASCII.GetBytes(serializedPostData);
The rest of the http call should work fine with the op's code. Below is the code for the IsCollection and IsDate methods:
private static bool IsCollection(object obj)
{
bool isCollection = false;
Type objType = obj.GetType();
if (!typeof(string).IsAssignableFrom(objType) && typeof(IEnumerable).IsAssignableFrom(objType))
{
isCollection = true;
}
return isCollection;
}
private static bool IsDate(object obj)
{
bool isDate = false;
if (typeof(DateTime) == obj.GetType() || typeof(DateTimeOffset) == obj.GetType())
{
isDate = true;
}
return isDate;
}
In my case this code will run in a SQL CLR C# Function, this is why I used only libraries available supported by SQL, thus my use of Uri.EscapeDataString instead of the more common HttpUtility.UrlEncode), but it works just fine.

send httprequest in order to receive some data

I have some difficulties in requesting an access token from an other server.
A request to get that is:
POST /auth/O2/token HTTP/1.1
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=client_credentials&scope=messaging:push&client_id=(YOUR_CLIENT_ID)&client_secret=(YOUR_CLIENT_SECRET)
and the response I want to obtain is like:
X-Amzn-RequestId: d917ceac-2245-11e2-a270-0bc161cb589d
Content-Type: application/json
{
"access_token":"Atc|MQEWYJxEnP3I1ND03ZzbY_NxQkA7Kn7Aioev_OfMRcyVQ4NxGzJMEaKJ8f0lSOiV-yW270o6fnkI",
"expires_in":3600,
"scope":"messaging:push",
"token_type":"Bearer"
}
I tried to get it through :
private String getAccessToken(String client_id,String client_secret)
{
HttpWebRequest httpWReq =
(HttpWebRequest)WebRequest.Create("http://api.amazon.com/auth/02/token");
Encoding encoding = new UTF8Encoding();
string postData = "grant_type=client_credentials";
postData += "&scope=messaging:push";
postData += "&client_id=" + client_id;
postData += "&client_secret=" + client_secret;
byte[] data = encoding.GetBytes(postData);
httpWReq.Method = "POST";
httpWReq.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
httpWReq.ContentLength = data.Length;
using (Stream stream = httpWReq.GetRequestStream()) // ***here I get this exception : Unable to connect to the remote server !!!****
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
String jsonresponse = "";
String temp = null;
while ((temp = reader.ReadLine()) != null)
{
jsonresponse += temp;
}
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, string>>(jsonresponse);
access_token = dict["access_token"];
String expires_in = dict["expires_in"];
}
return access_token;
}
I am getting this execption : Unable to connect to the remote server, when I tried to get request stream
Check this ...
its not 02 its O2
in your code , it may be the error
HttpWebRequest httpWReq =
(HttpWebRequest)WebRequest.Create("http://api.amazon.com/auth/**02**/token");
Try this
HttpWebRequest httpWReq =
(HttpWebRequest)WebRequest.Create("https://api.amazon.com/auth/o2/token");
Thank you ...
The first problem is that api.amazon.com/auth/02/token has nothing listening on port 80 (so it won't work); so probably it needs https (but if you provide reference to where this is documented we can better advise)
Secondly I think it'd be cleaner to replace the first part of your code with the following;
using (WebClient client = new WebClient())
{
byte[] response = client.UploadValues("https://api.amazon.com/auth/02/token", new NameValueCollection()
{
{ "scope", "messaging:push" },
{ "client_id", "1123" },
{ "client_secret", "2233"}
});
// handle response...
}

Categories