I have this generic handler in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace RequestResponse
{
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string function = context.Request.QueryString["function"];
Methods m = new Methods();
if(function.Equals("addition"))
{
int num1 = Convert.ToInt32(context.Request.QueryString["num1"]);
int num2 = Convert.ToInt32(context.Request.QueryString["num2"]);
int answer = m.addition(num1, num2);
context.Response.Write(answer);
}
if (function.Equals("subtraction"))
{
int num1 = Convert.ToInt32(context.Request.QueryString["num1"]);
int num2 = Convert.ToInt32(context.Request.QueryString["num2"]);
int answer = m.subtraction(num1, num2);
context.Response.Write(answer);
}
if(function.Equals("reverseString"))
{
string text = context.Request.QueryString["text"];
text = m.reverseString(text);
context.Response.Write(text);
}
if (function.Equals("CalculateMD5Hash"))
{
string text = context.Request.QueryString["text"];
text = m.CalculateMD5Hash(text);
context.Response.Write(text);
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
I also have this client application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
namespace Client
{
public partial class HomePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (TextBox_Function.Text.Equals("addition"))
{
int num1 = Convert.ToInt32(TextBox_Num1.Text);
int num2 = Convert.ToInt32(TextBox_Num2.Text);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:4000/Handler.ashx?function=" + TextBox_Function.Text + "&num1=" + num1 + "&num2=" + num2);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
String answer = response.ToString();
Session["answer"] = answer;
Response.Redirect("Results.aspx");
}
if (TextBox_Function.Text.Equals("subtraction"))
{
int num1 = Convert.ToInt32(TextBox_Num1.Text);
int num2 = Convert.ToInt32(TextBox_Num2.Text);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:4000/Handler.ashx?function=" + TextBox_Function.Text + "&num1=" + num1 + "&num2=" + num2);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
String answer = response.ToString();
Session["answer"] = answer;
Response.Redirect("Results.aspx");
}
if (TextBox_Function.Text.Equals("reverseString"))
{
String text = TextBox_Text.Text;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:4000/Handler.ashx?function=" + TextBox_Function.Text + "&text=" + text);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
String answer = response.ToString();
Session["answer"] = answer;
Response.Redirect("Results.aspx");
}
if (TextBox_Function.Text.Equals("CalculateMD5Hash"))
{
String text = TextBox_Text.Text;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:4000/Handler.ashx?function=" + TextBox_Function.Text + "&text=" + text);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
String answer = response.ToString();
Session["answer"] = answer;
Response.Redirect("Results.aspx");
}
}
}
}
Now, let us assume that in my client application, I provide "addition" as the function, "3" as num1 and "5" as num2.
Why does the answer generated (stored in variable answer) is:
System.Net.HttpWebResponse
What am I doing wrong? Please bear with me as I have never communicated between two applications in this way.
The problem is here:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
String answer = response.ToString();
You're just calling ToString() on the HttpWebResponse, whereas presumably what you really want to do is get the contents of the body of the response - which you'd do with something like this:
// It's important to dispose of responses...
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
string answer = reader.ReadToEnd();
}
}
Related
I have been working on a project and i used to use the v1 api for coinigy and loved the API. The problem is now with the new v2 API, I have been having an issue with trying to work the private API with the hmac_sha256 signature. I originally contacts coinigy support, but with little luck was not able to get it fully working (they did help, but never solved the issue, which is very weird). I built a simple test project in C# to perform a private call with the documentation they had for their api.
program.cs:
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
class Program
{
static void Main(string[] args)
{
string api_key = "API_KEY";
string api_secret = "API_SECRET";
CoinigyApiPrivateCall call = new CoinigyApiPrivateCall(api_key, api_decret);
string data = call.HttpPostRequest("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", null, "GET");
string body = null;
call.xcoinApiCall("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", ref body);
try
{
JObject j = JObject.Parse(data);
TickerDataCoinigy tt = new TickerDataCoinigy();
tt.volume = (string)j["volume"];
tt.last = (string)j["last"];
tt.high = (string)j["high"];
tt.low = (string)j["low"];
tt.ask = (string)j["ask"];
tt.bid = (string)j["bid"];
Console.WriteLine("Binance, BTC-LTC ticker data:");
Console.WriteLine("Volume: " + tt.volume);
Console.WriteLine("Last: " + tt.last);
Console.WriteLine("High: " + tt.high);
Console.WriteLine("Low: " + tt.low);
Console.WriteLine("ask: " + tt.ask);
Console.WriteLine("bid: " + tt.bid);
}
catch(Exception i)
{
Console.WriteLine("");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(data);
Console.ForegroundColor = ConsoleColor.White;
}
Console.ReadLine();
}
}
public class TickerDataCoinigy
{
public string volume;
public string last;
public string high;
public string low;
public string ask;
public string bid;
}
}
and also several versions (to see if a different way of calling the api would work) of a private call.
CoinigyApiPrivateCall.cs
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
public class CoinigyApiPrivateCall
{
private string api_key;
private string api_secret;
public CoinigyApiPrivateCall(string api_key, string api_secret)
{
this.api_key = api_key;
this.api_secret = api_secret;
}
public static double ConvertToUnixTimestamp(DateTime date)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalMilliseconds);
}
private string Hash_HMAC(string sKey, string sData)
{
byte[] rgbyKey = Encoding.ASCII.GetBytes(sKey);
using (var hmacsha256 = new HMACSHA256(rgbyKey))
{
byte[] inf = hmacsha256.ComputeHash(Encoding.ASCII.GetBytes(sData));
return (ByteToString(inf));
}
}
private string ByteToString(byte[] rgbyBuff)
{
string sHexStr = "";
for (int nCnt = 0; nCnt < rgbyBuff.Length; nCnt++)
{
sHexStr += rgbyBuff[nCnt].ToString("x2"); // Hex format
}
return (sHexStr);
}
private byte[] StringToByte(string sStr)
{
byte[] rgbyBuff = Encoding.ASCII.GetBytes(sStr);
return (rgbyBuff);
}
public string HttpPostRequest(string url, string au, List<KeyValuePair<string, string>> postdata, string httpType)
{
var client = new HttpClient();
//client.DefaultRequestHeaders.Add("User-Agent", ua);
//client.DefaultRequestHeaders.Add("X-API-KEY", api_key);
//client.DefaultRequestHeaders.Add("X-API-SECRET", api_secret);
string time = Convert.ToString(ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime()));
FormUrlEncodedContent content = null;
string data = null;
if (postdata != null)
{
content = new FormUrlEncodedContent(postdata);
var output = Newtonsoft.Json.JsonConvert.SerializeObject(postdata);
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url + output;
}
else
{
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url;
}
string sign = Hash_HMAC(api_secret, data);
client.DefaultRequestHeaders.Add("X-API-SIGN", sign);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", time);
HttpResponseMessage response = null;
if (httpType.ToUpper() == "POST")
{
response = client.PostAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "GET")
{
response = client.GetAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
if (httpType.ToUpper() == "PUT")
{
response = client.PutAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "DELETE")
{
response = client.DeleteAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
return response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().Result
: "ERROR:" + response.StatusCode + " " + response.ReasonPhrase + " | " + response.RequestMessage;
}
public JObject xcoinApiCall(string sEndPoint, string sParams, ref string sRespBodyData)
{
string sAPI_Sign = "";
string sPostData = sParams;
string sHMAC_Key = "";
string sHMAC_Data = "";
string sResult = "";
double nNonce = 0;
HttpStatusCode nCode = 0;
sPostData += "&endpoint=" + Uri.EscapeDataString(sEndPoint);
try
{
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://api.coinigy.com/api/v2/" + sEndPoint);
byte[] rgbyData = Encoding.ASCII.GetBytes(sPostData);
nNonce = ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime());
sHMAC_Key = this.api_secret;
sHMAC_Data = api_key + nNonce.ToString() + "GET" + "/api/v2/" + sEndPoint;
//sHMAC_Data = sEndPoint + (char)0 + sPostData + (char)0 + nNonce.ToString();
sResult = Hash_HMAC(sHMAC_Key, sHMAC_Data);
//sAPI_Sign = Convert.ToBase64String(StringToByte(sResult));
sAPI_Sign = sResult;
Request.Headers.Add("X-API-SIGN", sAPI_Sign);
Request.Headers.Add("X-API-TIMESTAMP", nNonce.ToString());
Request.Method = "GET";
Request.ContentType = "application/x-www-form-urlencoded";
Request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
/*Request.ContentLength = rgbyData.Length;
using (var stream = Request.GetRequestStream())
{
stream.Write(rgbyData, 0, rgbyData.Length);
} */
var Response = (HttpWebResponse)Request.GetResponse();
sRespBodyData = new StreamReader(Response.GetResponseStream()).ReadToEnd();
return (JObject.Parse(sRespBodyData));
}
catch (WebException webEx)
{
using (HttpWebResponse Response = (HttpWebResponse)webEx.Response)
{
nCode = Response.StatusCode;
using (StreamReader reader = new StreamReader(Response.GetResponseStream()))
{
sRespBodyData = reader.ReadToEnd();
try
{
return (JObject.Parse(sRespBodyData));
}
catch(Exception i)
{
}
}
}
}
return (null);
}
}
}
If anyone that has any knowledge on this that could help, I would be very grateful.
Edit: I used the code from Joe to see if the unauthorized issue could be fixed and I got this result:
{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content:
System.Net.Http.StreamContent, Headers:
{
Date: Sun, 29 Jul 2018 19:19:36 GMT
Content-Length: 0
}}
I am using this code to perform the http call:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Coinigy_v2_api_2018.Functions;
using System.Net.Http;
namespace Coinigy_v2_api_test
{
class Program
{
static void Main(string[] args)
{
ApiRequest req = new ApiRequest();
req.BaseUrl = "https://api.coinigy.com";
req.Body = "";
req.Method = "GET";
req.Secret = "secret";
req.Key = "key";
req.Endpoint = "/api/v2/private/exchanges";
string signature = req.Signature;
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-API-SIGN", signature);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", req.Timestamp);
response = client.GetAsync(req.BaseUrl + req.Endpoint).Result;
}
string r = null;
if (response.IsSuccessStatusCode)
{
r = response.Content.ReadAsStringAsync().Result;
}
Console.WriteLine(r);
Console.ReadLine();
}
}
}
again thank you in advance!
API documentation can be found here: https://api.coinigy.com/api/v2/docs/#/
2019-08-28: Latest update is that the endpoint must require the query parameter unencoded when generating the signature.
The very first thing to check is to make sure you are using a V2 api key/secret. The old V1 keys will not work with the V2 api. If you upgrade your subscription, you will likely need to generate a new key for it to take effect.
Here is a class that should help out if that doesn't solve the problem:
public class ApiRequest
{
public string BaseUrl { get; set; }
public string Endpoint { get; set; }
public string Key { get; set; }
public string Secret { get; set; }
public string Method { get; set; }
public string Body { get; set; }
public string Timestamp { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
/// <summary>
/// Each API request needs to be signed so the sender can be identified.
/// This property generates the signature based on the current request.
/// </summary>
public string Signature
{
get
{
var asciiEncoding = new ASCIIEncoding();
var hmac = new HMACSHA256(asciiEncoding.GetBytes(Secret));
string signature = Key + Timestamp + Method.ToUpper() + Endpoint + (Body ?? string.Empty);
byte[] signatureBytes = asciiEncoding.GetBytes(signature);
byte[] hashedSignatureBytes = hmac.ComputeHash(signatureBytes);
string hexSignature = string.Join(string.Empty, Array.ConvertAll(hashedSignatureBytes, hb => hb.ToString("X2")));
return hexSignature;
}
}
}
If you set those values properly, you should be able to generate the proper signature.
For the parameter values, start with something like this and compare to the signature I've produced to make sure your signature function is working properly:
BaseUrl : https://api.coinigy.com
Endpoint : /api/v2/private/exchanges?pythagoreanTheorem=a%5E2%2Bb%5E2%3Dc%5E2
Key : keykeykeykeykeykeykeykeykeykeyke
Secret : secretsecretsecretsecretsecretse
Method : GET
Timestamp : 1532718830 (which is 2018-07-27T19:13:50.6694555Z)
Body : (empty string)
Signature : B618C0B3C92632C701D7CEFC00AC9C8A0771989B21E00D61D4945F79239D2F87
Here is a bonus python3 version that will perform the entire process: https://gist.github.com/phillijw/1f78c8bafdce3a71a0b2ef9d4f5942a1
Actually this is not a question, but an answer for those that are trying to use AWS TranslateText without SDK. I have had many problems until I got a running version.
In my opinion, the AWS documentation for this service is not complete and there are not many examples to check (at least for .Net).
At first, I thought I was not generating the correct V4 signature, but after checking the steps and values once again, I decided to use Postman to call the service. It was very helpful.
Postman can generate the AWS signature! (yeah, I did not know) so finally I noticed the signature value was not the problem.
Checking the request I could see the headers needed and some of its values.
The problem in my case was that I was not sending the "x-amz-target" header.
And by chance I found that the value for this header must be "AWSShineFrontendService_20170701.TranslateText"
(I saw a similar value here https://rdrr.io/cran/aws.translate/src/R/translateHTTP.R)
This other link was also helpful
Ivona Request Signing Issue - signature does not match (AWS Signature Version 4)
So now I have a running version, I want to share my .Net code. I hope it helps :) !!
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;
namespace AWS_TranslateTextTest
{
class AWS_TranslateText
{
// Replace this with your own values
const string AccessKey = "AKI_ADD_YOUR_ACCESSKEY";
const string SecretKey = "ADD_YOUR_SECRETKEY";
static void Main()
{
try
{
string text = "Translate this text from English to German.";
string sourceLang = "en";
string targetLang = "de";
string responseText = TranslateText(text, sourceLang, targetLang);
JObject json = JObject.Parse(responseText);
string translatedText = ""; // to do read response from json or responseText
if (json.ToString().Contains("TranslatedText")){
//To access to the properties in "dot" notation use a dynamic object
dynamic obj = json;
translatedText = obj.TranslatedText.Value;
Console.WriteLine("TranslatedText is: {0}", translatedText);
}
else{
Console.WriteLine("TranslatedText not found in response.");
throw new Exception(json.ToString());
}
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
if (ex.Response != null){
foreach (string header in ex.Response.Headers)
{
Console.WriteLine("{0}: {1}", header, ex.Response.Headers[header]);
}
using (var responseStream = ex.Response.GetResponseStream())
{
if (responseStream != null)
{
using (var streamReader = new StreamReader(responseStream))
{
Console.WriteLine(streamReader.ReadToEnd());
}
}
} }
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static string TranslateText(string text, string sourceLang, string targetLang)
{
var date = DateTime.UtcNow;
const string algorithm = "AWS4-HMAC-SHA256";
const string regionName = "eu-west-1";
const string serviceName = "translate";
const string method = "POST";
const string canonicalUri = "/";
const string canonicalQueryString = "";
const string x_amz_target_header = "AWSShineFrontendService_20170701.TranslateText";
const string contentType = "application/x-amz-json-1.1";
const string host = serviceName + "." + regionName + ".amazonaws.com";
var obj = new
{
SourceLanguageCode = sourceLang,
TargetLanguageCode = targetLang,
Text = text
};
var requestPayload = new JavaScriptSerializer().Serialize(obj);
var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));
var dateStamp = date.ToString("yyyyMMdd");
var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);
var bytes = ToBytes(requestPayload);
var headers = new SortedDictionary<string, string>
{
{"content-length", bytes.Length.ToString()},
{"content-type", contentType},
{"host", host},
{"x-amz-date", requestDate},
{"x-amz-target", x_amz_target_header}
};
string canonicalHeaders =
string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
string signedHeaders =
string.Join(";", headers.Select(x => x.Key.ToLowerInvariant() ));
// 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)));
// 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);
// 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));
// 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
string endpoint = "https://" + host; // + canonicalUri ;
var webRequest = WebRequest.Create(endpoint);
webRequest.Method = method;
webRequest.Timeout = 20000;
webRequest.ContentType = contentType;
webRequest.Headers.Add("X-Amz-Date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("X-Amz-Target", x_amz_target_header);
webRequest.ContentLength = bytes.Length;
using (Stream newStream = webRequest.GetRequestStream())
{
newStream.Write(bytes, 0, bytes.Length);
newStream.Flush();
}
var response = (HttpWebResponse)webRequest.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (var streamReader = new StreamReader(responseStream))
{
string res = streamReader.ReadToEnd();
return res;
}
}
}
return null;
}
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)
{
return SHA256.Create().ComputeHash(bytes);
}
private static byte[] HmacSha256(String data, byte[] key)
{
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
}
}
Before I get into the code let me explain what i'm trying to do. It's a simple checklist against an API, the api has a limit and I figured a way to break the limit with changing my ip easily from my router. It works great most of the time but at some point after re-connecting successfully the worker stops and I have to click the button again.
Here's the code, first the Form class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyNameChecker
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void chk_Click(object sender, EventArgs e)
{
if (!checkNames.IsBusy)
{
checkNames.RunWorkerAsync();
}
}
int last = 0;
private void checkNames_DoWork(object sender, DoWorkEventArgs e)
{
string namesList = "";
string[] namesArray;
if (names.InvokeRequired) names.Invoke(new MethodInvoker(delegate { namesList = names.Text; }));
else namesList = names.Text;
if (!string.IsNullOrEmpty(namesList))
{
namesArray = namesList.Replace("\r","").Split('\n');
while (last < namesArray.Length)
{
string tempStr = NameChecker.check(namesArray[last].Replace("\r", "").Replace("\n", ""));
if (tempStr == "available")
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\Names\available.txt", true)) file.WriteLine(namesArray[last]);
last++;
}
else if (tempStr == "unavailable" || tempStr == "skep")
{
last++;
}
else
{
while(!NameChecker.reconnect());
}
}
if (last >= namesArray.Length) last = 0;
}
}
}
}
Second MyNameChecker class:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;
namespace MyNameChecker
{
class NameChecker
{
public static string check(string name)
{
if (string.IsNullOrEmpty(name)) return "skep";
string url = "https://example.com/api";
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.AllowAutoRedirect = false;
webRequest.Method = "POST";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/json; charset=UTF-8";
ASCIIEncoding encoding = new ASCIIEncoding();
string stringData = "{\"name\":\"" + name + "\"}";
byte[] data = encoding.GetBytes(stringData);
webRequest.ContentLength = data.Length;
webRequest.GetRequestStream().Write(data, 0, data.Length);
webRequest.Timeout = 60000;
try
{
// Get the response ...
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (string.IsNullOrEmpty(webResponse.Headers["RequestNum"])) return "retry";
else return status(webResponse);
}
}
catch (WebException ex)
{
var res = (HttpWebResponse)ex.Response;
if (string.IsNullOrEmpty(res.Headers["RequestNum"])) return "retry";
else return status(res);
}
catch (Exception ex)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\Names\Exceptions.txt", true)) file.WriteLine(ex.Message);
return "retry";
}
return "retry";
}
private static string status(HttpWebResponse res)
{
switch((int)res.StatusCode)
{
case 201:
return "available";
case 400:
return "unavailable";
default:
return "retry";
}
}
public static bool reconnect()
{
string url = "http://router.lan/cgi/b/is/_pppoe_/ov/?be=0&l0=1&l1=1&name=Internet";
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.AllowAutoRedirect = false;
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.KeepAlive = true;
System.Net.ServicePointManager.Expect100Continue = false;
ASCIIEncoding encoding = new ASCIIEncoding();
string stringData = "0=12&1=Internet&32=1";
byte[] data = encoding.GetBytes(stringData);
webRequest.ContentLength = data.Length;
webRequest.GetRequestStream().Write(data, 0, data.Length);
webRequest.Timeout = 25000;
try
{
// Get the response ...
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
{
// Get the body stream
string body = new System.IO.StreamReader(webResponse.GetResponseStream()).ReadToEnd();
if (body.Contains("Uptime:")) return true;
return false;
}
return false;
}
catch (WebException ex)
{
var res = (HttpWebResponse)ex.Response;
string body = new System.IO.StreamReader(res.GetResponseStream()).ReadToEnd();
if (body.Contains("Uptime:")) return true;
return false;
}
catch (Exception ex)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\Names\Exceptions.txt", true)) file.WriteLine(ex.Message);
return false;
}
return false;
}
}
}
I tried everything I could from increasing the timeout to catch all exceptions but there's no exception recorded? I'm unable to figure this problem. Usually I go to sleep and let it do it's work but this is just not working as expected.
BTW I used fiddler to debug the requests and there was an odd header Expect: 100-continue i don't know if this has anything to do with the breaking but I thought it's better to mention it.
I am completely new to this kind of programming so I don't really know if there is an answer to this already, but I weren't able to find it. So I am testing to see if I can get a dry-run gcm message to work without errors.
The error I get is the error 400 Invalid Request, and it's saying something about the json being invalid, so I have assumed the problem has to do with string manipulation or the definition of postdata, but I can't figure it out. Most of the code is just copy pasted anyway so one could believe that others in a similar situation will get the same error, if they copy from the same source.
And also I have put in actual values for the "lorem"s.
This is the only code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Web.Script.Serialization;
namespace ServerGMC
{
public class ServerGMC
{
static void Main ()
{
// Prepares and calls the function to send message
List<string> RedIdList = new List<string>(1) { "aaaaaaaaaaaaaaaaaaaaaaaa" };
RedIdList.TrimExcess();
Console.WriteLine(SendNotification(RedIdList, "HelloWorld", "test", 220299));
Console.Read();
}
static public string SendNotification(List<string> deviceRegIds, string message, string title, long id)
{
try
{
string regIds = string.Join("\",\"", deviceRegIds);
string AppId = "lorem";
var SenderId = "lorem";
NotificationMessage nm = new NotificationMessage();
nm.Title = title;
nm.Message = message;
nm.ItemId = id;
var value = new JavaScriptSerializer().Serialize(nm);
WebRequest wRequest;
wRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
wRequest.Method = "post";
wRequest.ContentType = " application/json;charset=UTF-8";
wRequest.Headers.Add(string.Format("Authorization: key={0}", AppId));
wRequest.Headers.Add(string.Format("Sender: id={0}", SenderId));
string postData = "{\"collapse_key\":\"standard\",\"time_to_live\":108,\"delay_while_idle\":true,\"dry_run\":true,\"data\": { \"message\" : " + "\"" + value + "\",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\"},\"registration_ids\":[\"" + regIds + "\"]}";
//string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&date.time=" + System.DateTime.Now.ToString() + "®istration_ids=" + regIds + "";
Console.WriteLine(postData);
Byte[] bytes = Encoding.UTF8.GetBytes(postData);
wRequest.ContentLength = bytes.Length;
Stream stream = wRequest.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();
WebResponse wResponse = wRequest.GetResponse();
stream = wResponse.GetResponseStream();
StreamReader reader = new StreamReader(stream);
String response = reader.ReadToEnd();
HttpWebResponse httpResponse = (HttpWebResponse)wResponse;
string status = httpResponse.StatusCode.ToString();
reader.Close();
stream.Close();
wResponse.Close();
if (status == "")
{
return response;
}
else
{
return "";
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.WriteLine();
return "";
}
}
private class NotificationMessage
{
public string Title;
public string Message;
public long ItemId;
}
}
}
The postData isn't properly formatted in JSON. If you check it out using an online formatting tool, it looks like this
{
"collapse_key":"standard",
"time_to_live":108,
"delay_while_idle":true,
"dry_run":true,
"data":{
"message":"{"Title":"test",
"Message":"HelloWorld",
"ItemId":220299}",
"time":"22/04/2016 13:04:38"
},
"registration_ids":["aaaaaaaaaaaaaaaaaaaaaaaa"]
}
You can either remove the data.message node and place its properties in data, or use a 3rd-party JSON parser or System.Web.Helpers.Json.Decode (which were suggested in this issue)
Hopefully this helps with the issue.
Happy coding!
After managing to load data to my Rails Server through c# (check here to know what i am talking about), i am now trying to upload a file to that same server, along with other data.
In Ruby, I am able to do this with the code :
require 'HTTMultiParty'
class ReceiptCreate
include HTTMultiParty
# Log to file
# debug_output File.new("httparty1.log", "w+")
base_uri "localhost:3000"
format :json
headers "Accept" => "application/json"
def initialize
end
def post(machine_serial,filepath,tag_number,token)
options = { body:
{receipt:
{tag_number:tag_number,
receipt_file: File.new(filepath),
ispaperduplicate:0
},
machine:
{serial_number: machine_serial,
safe_token: token
}
}
}
self.class.post('/receipts', options)
end
end
receipt = ReceiptCreate.new()
filename1 = "C:\\filename1.pdf"
filename2 = "C:\\filename2.pdf"
response=receipt.post("2803433",filename2,"p94tt7w","123")
puts response
an when I inspect the parameters on the rails server i see
Parameters: {"receipt"=>{"tag_number"=>"p94tt7w", "receipt_file"=>#<ActionDispatch::Http::UploadedFile:0x4183ea8 #original_filename="Invoice.pdf", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"receipt[receipt_file]\"; filename=\"Invoice.pdf\"\r\nContent-Length: 11653\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n", #tempfile=#<File:C:/Users/diogo/AppData/Local/Temp/RackMultipart20130103-18168-efiqia>>, "ispaperduplicate"=>"0"}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}}
But if i try to do the same with my c# code below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RestSharp;
using System.Web.Script.Serialization;
using System.IO;
namespace RonRestClient
{
class templateRequest
{
public Receipt receipt;
public class Receipt
{
public float total;
public String tag_number;
public bool ispaperduplicate = true;
public byte[] receipt_file;
public Receipt(float total, String tagnr, string filepath)
{
this.total = total;
this.tag_number = tagnr;
this.receipt_file = File.ReadAllBytes(filepath);
}
};
public Machine machine;
public class Machine
{
public String serial_number;
public String safe_token;
public Machine(String machinenr, String safe_token)
{
this.serial_number = machinenr;
this.safe_token = safe_token;
}
};
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\filename2.pdf";
string tagnr = "p94tt7w";
string machinenr = "2803433";
string safe_token = "123";
float total = 100;
templateRequest req = new templateRequest();
req.receipt = new templateRequest.Receipt(total, tagnr, path);
req.machine = new templateRequest.Machine(machinenr, safe_token);
//string json_body = JsonConvert.SerializeObject(req);
//string json_body = new JavaScriptSerializer().Serialize(req);
//var json_body = "{\"receipt\" : {\"total\":"+total+", \"tag_number\":\""+tagnr+"\",\"ispaperduplicate\":true},\"machine\":{\"serial_number\": \""+machinenr+"\",\"safe_token\": \""+safe_token+"\"}}";
var client = new RestClient("http://localhost:3000/receipts");
var request = new RestRequest(Method.POST);
//set request Body
request.AddHeader("Content-type", "application/json");
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
request.AddBody(req);
//request.AddParameter("application/json", json_body, ParameterType.RequestBody);
// easily add HTTP Headers
// add files to upload (works with compatible verbs)
//request.AddFile("receipt/receipt_file",path);
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
if(response.ErrorMessage !="") content += response.ErrorMessage;
response_box.Text = content;
}
}
}
I get this
Parameters: {"receipt"=>{"total"=>100, "tag_number"=>"p94tt7w", "ispaperduplicate"=>true, "receipt_file"=>[37, 80, [n3...nX], 10]}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}}
This seems to mean basically that Restsharp just thinks that my file is just another field.
RestSharp seems to have a method to add files request.AddFile("receipt/receipt_file",path);, and i believe that this should probably be the way to go...but when i just try and add the file, i get an error message saying :
This property cannot be set after writing has started.
Do I need to set each attribute of the file separately?
EDIT
Meanwhile i found this post, changed my code to :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RestSharp;
using System.Web.Script.Serialization;
using System.IO;
using System.Net;
namespace RonRestClient
{
class templateRequest
{
public Receipt receipt;
public class Receipt
{
//public float total;
public String tag_number;
public bool ispaperduplicate = true;
//public byte[] receipt_file;
public Receipt(String tagnr)
{
//this.total = total;
this.tag_number = tagnr;
// this.receipt_file = File.ReadAllBytes(filepath);
}
};
public Machine machine;
public class Machine
{
public String serial_number;
public String safe_token;
public Machine(String machinenr, String safe_token)
{
this.serial_number = machinenr;
this.safe_token = safe_token;
}
};
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\filename2.pdf";
string tagnr = "p94tt7w";
string machinenr = "2803433";
string safe_token = "123";
float total = 100;
templateRequest req = new templateRequest();
req.receipt = new templateRequest.Receipt(tagnr);
req.machine = new templateRequest.Machine(machinenr, safe_token);
var request = new RestRequest("/receipts",Method.POST);
request.AddParameter("receipt[total]", total);
request.AddParameter("receipt[tag_number]", tagnr);
request.AddParameter("machine[serial_number]", machinenr);
request.AddParameter("machine[safe_token]", safe_token);
request.AddFile("receipt[receipt_file]", File.ReadAllBytes(path), "Invoice.pdf", "application/octet-stream");
// Add HTTP Headers
request.AddHeader("Content-type", "application/json");
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
//set request Body
//request.AddBody(req);
// execute the request
//calling server with restClient
RestClient restClient = new RestClient("http://localhost:3000");
restClient.ExecuteAsync(request, (response) =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
//upload successfull
MessageBox.Show("Upload completed succesfully...\n" + response.Content);
}
else
{
//error ocured during upload
MessageBox.Show(response.StatusCode + "\n" + response.StatusDescription);
}
});
}
}
}
and now am getting the parameters :
Parameters: {"receipt"=>{"total"=>"100", "tag_number"=>"p94tt7w", "receipt_file"=>#<ActionDispatch::Http::UploadedFile:0x3db42d8 #original_filename="Invoice.pdf", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"receipt[receipt_file]\"; filename=\"Invoice.pdf\"\r\nContent-Type: application/octet-stream\r\n", #tempfile=#<File:C:/Users/diogo/AppData/Local/Temp/RackMultipart20130103-18168-9mbt3h>>}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}}
Along with an HTTP 422 - Unprocessable Entity error.
If I am to compare these parameters with the ones that i have working from the ruby code, now the only difference seems to be that this last message does not have the Content-length and Content-Transfer-Encoding fields...
Do you have any idea on how i might add the attributes?
This was a fight... In the end I discovered two different ways of solving this problem. The irony of it, as so many of coding problems, was that all i had to do was setting the right parameters in first place...Just one missing parameter cost me more than 4 hours..
Both detailed below :
1 - Use RestSharp (the total field shouldn't be there, and the ispaperduplicate field was missing)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RestSharp;
using System.Web.Script.Serialization;
using System.IO;
using System.Net;
namespace RonRestClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\filename2.pdf";
//localhost settings
string requestHost = #"http://localhost:3000/receipts";
string tagnr = "p94tt7w";
string machinenr = "2803433";
string safe_token = "123";
// Do it with RestSharp
templateRequest req = new templateRequest();
req.receipt = new templateRequest.Receipt(tagnr);
req.machine = new templateRequest.Machine(machinenr, safe_token);
var request = new RestRequest("/receipts", Method.POST);
request.AddParameter("receipt[tag_number]", tagnr);
request.AddParameter("receipt[ispaperduplicate]", 0);
request.AddParameter("machine[serial_number]", machinenr);
request.AddParameter("machine[safe_token]", safe_token);
request.AddFile("receipt[receipt_file]", File.ReadAllBytes(path), Path.GetFileName(path), "application/octet-stream");
// Add HTTP Headers
request.AddHeader("Content-type", "application/json");
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
//set request Body
//request.AddBody(req);
// execute the request
//calling server with restClient
RestClient restClient = new RestClient("http://localhost:3000");
restClient.ExecuteAsync(request, (response) =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
//upload successfull
MessageBox.Show("Upload completed succesfully...\n" + response.Content);
}
else
{
//error ocured during upload
MessageBox.Show(response.StatusCode + "\n" + response.StatusDescription);
}
});
}
}
}
2 - Use FileStream with HttpWebRequest (thank you Clivant)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RestSharp;
using System.Web.Script.Serialization;
using System.IO;
using System.Net;
namespace RonRestClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\Projectos\My Training Samples\Adobe Sample\RBO1574.pdf";
//localhost settings
string requestHost = #"http://localhost:3000/receipts";
string tagnr = "p94tt7w";
string machinenr = "2803433";
string safe_token = "123";
FileStream fs1 = File.OpenRead(path);
long filesize = fs1.Length;
fs1.Close();
// Create a http request to the server endpoint that will pick up the
// file and file description.
HttpWebRequest requestToServerEndpoint =
(HttpWebRequest)WebRequest.Create(requestHost);
string boundaryString = "FFF3F395A90B452BB8BEDC878DDBD152";
string fileUrl = path;
// Set the http request header \\
requestToServerEndpoint.Method = WebRequestMethods.Http.Post;
requestToServerEndpoint.ContentType = "multipart/form-data; boundary=" + boundaryString;
requestToServerEndpoint.KeepAlive = true;
requestToServerEndpoint.Credentials = System.Net.CredentialCache.DefaultCredentials;
requestToServerEndpoint.Accept = "application/json";
// Use a MemoryStream to form the post data request,
// so that we can get the content-length attribute.
MemoryStream postDataStream = new MemoryStream();
StreamWriter postDataWriter = new StreamWriter(postDataStream);
// Include value from the tag_number text area in the post data
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",
"receipt[tag_number]",
tagnr);
// Include ispaperduplicate text area in the post data
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",
"receipt[ispaperduplicate]",
0);
// Include value from the machine number in the post data
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",
"machine[serial_number]",
machinenr);
// Include value from the machine token in the post data
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",
"machine[safe_token]",
safe_token);
// Include the file in the post data
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n"
+ "Content-Length: \"{2}\"\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "Content-Transfer-Encoding: binary\r\n\r\n",
"receipt[receipt_file]",
Path.GetFileName(fileUrl),
filesize);
postDataWriter.Flush();
// Read the file
FileStream fileStream = new FileStream(fileUrl, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
postDataStream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
postDataWriter.Write("\r\n--" + boundaryString + "--\r\n");
postDataWriter.Flush();
// Set the http request body content length
requestToServerEndpoint.ContentLength = postDataStream.Length;
// Dump the post data from the memory stream to the request stream
Stream s = requestToServerEndpoint.GetRequestStream();
postDataStream.WriteTo(s);
postDataStream.Close();
}
}
}