I am looking for a simple example of accessing the Amazon Mechanical Turk web service in C#. I know there is a SDK for C# but I want to understand the basic mechanics before using that.
Here is the simplest code example I've come up with to access Mechanical Turk. It creates the signature and calls the GetAccountBalance operation.
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace TurkTest {
class Program {
static void Main(string[] args) {
const string SERVICE_NAME = "AWSMechanicalTurkRequester"; // requester service for MTurk
const string TIMESTAMP_FORMAT = "yyyy-MM-ddTHH:mm:ss.fffZ";
// Modify these with your values.
const string operation = "GetAccountBalance";
const string accessKey = "<Your access key>";
const string secretAccessKey = "<Your secret access key>";
// Millisecond values in the timestamp string can result in intermittent BadClaimsSupplied errors.
// Get the current UTC time and use that to create a new time with milliseconds set to zero to avoid this case.
DateTime now = DateTime.UtcNow;
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, DateTimeKind.Utc);
string timeStamp = now.ToString(TIMESTAMP_FORMAT, CultureInfo.InvariantCulture);
// Create the hash-based messaged authentication algorithm (SHA1) using our secret access key as the key.
var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(secretAccessKey));
// Combine the service name, operation and timestamp and then hash them to produce the signature.
var dataBytes = Encoding.UTF8.GetBytes(SERVICE_NAME + operation + timeStamp);
string signature = Convert.ToBase64String(hmac.ComputeHash(dataBytes));
// Build the URL to send to Amazon
string url =
#"https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester&AWSAccessKeyId={0}&Version=2012-03-25&Operation={1}&Signature={2}&Timestamp={3}";
url = string.Format(url, accessKey, operation, signature, timeStamp);
// Send a request and write the response to the console.
using (WebClient client = new WebClient()) {
using (StreamReader reader = new StreamReader(client.OpenRead(url))) {
Console.WriteLine(reader.ReadToEnd());
}
}
Console.Read();
}
}
}
Related
I'm writing a Discord Bot (Discord.net) and I found myself requiring to access some data on a google sheet using their APIs. Being that I thought it would be best to actually separate those two in two different class files I have tried summoning the Main method of the Google APIs into my program (after having renamed it "Sheets") like this in my Program.cs:
using Discord;
using Discord.WebSocket;
using System;
using System.IO;
using System.Threading.Tasks;
namespace WoM_Balance_Bot
{
public class Program
{
public static void Main(string[] args)
{
GoogleAPI GSheet = new GoogleAPI();
GSheet.Sheets();
new Program().MainAsync().GetAwaiter().GetResult();
}
private DiscordSocketClient _client;
public async Task MainAsync()
{
_client = new DiscordSocketClient();
_client.MessageReceived += CommandHandler;
_client.Log += Log;
var token = File.ReadAllText("bot-token.txt");
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
// Block this task until the program is closed.
await Task.Delay(-1);
}.......ecc
I tried writing the parameters to pass here in these parentheses like "string" and "args" but either I get the syntax wrong or I have a very wrong idea about what to pass exactly.
This is the actual content of GoogleAPI.cs, which is the other class file I created that has the Google Sheet APIs:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace WoM_Balance_Bot
{
public class GoogleAPI
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-dotnet-quickstart.json
private static readonly string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
private static readonly string ApplicationName = "wombankrolls";
public static void Sheets(string[] args)
{
UserCredential credential;
Console.WriteLine("if you read this then it's good");
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define request parameters.
String spreadsheetId = "16W56LWqt6wDaYAU5xNdTWCdaY_gkuQyl4CE1lPpUui4";
String range = "Class Data!G163:I";
SpreadsheetsResource.ValuesResource.GetRequest request =
service.Spreadsheets.Values.Get(spreadsheetId, range);
// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
ValueRange response = request.Execute();
IList<IList<Object>> values = response.Values;
/*
if (values != null && values.Count > 0)
{
Console.WriteLine("Name, Major");
foreach (var row in values)
{
// Print columns A and E, which correspond to indices 0 and 4.
Console.WriteLine("{0}, {1}", row[0], row[4]);
}
}
else
{
Console.WriteLine("No data found.");
}
Console.Read();
*/
}
}
}
I have modified it from the quickstart given by Google in a way that I thought it made sense but I still get in the end the same error:
There is no argument given that corresponds to the required formal parameter 'args' of 'GoogleAPI.Sheets(string[])'
as the user "David L" wrote in the comments:
As a general rule of thumb, if you do not use an argument, remove it. C# helps enforce this paradigm by throwing a compiler error if your method expects an argument and you do not provide one, which is exactly what is happening here.
It was my bad as I was under the impression of the total opposite during an API implementation. I would like to always target a clean code as a result and keeping stuff that I will not use was my bad. Thank you David!
I am trying to embed a Power BI report to a custom asp.net application. I have followed Microsoft's developer guidance, but I am hitting some odd issues that are not documented very well on the web.
Here is my current code:
using System;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Rest;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Collections.Generic;
using Microsoft.Identity;
using System.Web;
using System.Security.Cryptography.X509Certificates;
namespace AppOnlyAuthPBI.Models
{
public class PBIEmbeddedManager
{
private static string resourceUriPowerBi = "https://analysis.windows.net/powerbi/api";
private static string urlPowerBiRestApiRoot = "https://api.powerbi.com/";
const string aadRootAuthorizationEndpoint = "https://login.windows.net/";
static readonly string tenantId = ConfigurationManager.AppSettings["tenant-id"];
static readonly string aadTenantAuthorizationEndpoint = aadRootAuthorizationEndpoint +
tenantId + "/";
private static string applicationId = ConfigurationManager.AppSettings["application-id"];
private static string applicationSecret = ConfigurationManager.AppSettings["application-secret"];
private static string workspaceId = ConfigurationManager.AppSettings["app-workspace-id"];
private static string reportId = ConfigurationManager.AppSettings["report-id"];
static string GetAccessToken()
{
var authContext = new AuthenticationContext(aadTenantAuthorizationEndpoint);
var clientCredential = new ClientCredential(applicationId, applicationSecret);
return authContext.AcquireTokenAsync(resourceUriPowerBi, clientCredential).Result.AccessToken;
}
private static PowerBIClient GetPowerBiClient()
{
var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiRestApiRoot), tokenCredentials);
}
public static async Task<ReportEmbeddingData> GetReportEmbeddingData()
{
PowerBIClient pbiClient = GetPowerBiClient();
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
var embedUrl = report.EmbedUrl;
var reportName = report.Name;
GenerateTokenRequest generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
return new ReportEmbeddingData
{
reportId = reportId,
reportName = reportName,
embedUrl = embedUrl,
accessToken = embedToken
};
}
}
}
I am having issues ReportEmbeddingData() method.
var report = await pbiClient.Reports.GetReportInGroupAsync(workspaceId, reportId);
Here I am getting two errors, both stating cannot convert string to System.Guid. So I tried to parse them like so...
Guid.Parse(workspaceId)
Guid.Parse(reportId)
But, doing this then causes another error to appear which has no information surrounding it on the web...
string embedToken =
(await pbiClient.Reports.GenerateTokenInGroupAsync(workspaceId,
report.Id,
generateTokenRequestParameters)).Token;
I get an error on Reports.GenerateTokenInGroupAsync saying the following: "CS1929 - 'IReportsOperations' does not contain a definition for for 'GenerateTokenInGroupAsync' and the best extension method overload 'IDashboardOperationExtensions, guid, guid, GenerateTokenPermissions, CancellationToken' requires a receiver type of 'IDashboardsOperation'
To me it seems like I am missing a nuGet package, but I have verified this and everything is working as intended there and I have the required using statements applied as well.
Has anyone encountered this or does anyone know how to correct this? It seems really odd to me that Microsoft is recommending this code and I am hitting an error, leading me to believe that I am the one making the mistake but it is alluding me.
Thank you~
Use GenerateTokenInGroupWithHttpMessagesAsync()
So i am fiddling with this website's IPN function to see if i wan't to incorporate it to some dumb project my friends and i are working on. To be honest i don't know much C# in depth, i'm fairly new to the language (a few months of coding practice).
This is the PHP sample they give out on how to use it:
https://github.com/Rocketr/rocketrnet-ipn-php/blob/master/example_rocketr_ipn.php
I am trying to make a receiver like that in MVC 5. I have the Model setup with a function when the IPN hits the server page to process the request but it seems to just fail out everytime and not write any raw data i am trying to capture to the logs.
// GET: Purchases/Incoming
public void Incoming()
{
var ipnDebugLog = HttpRuntime.AppDomainAppPath + "/Logs/IPN/debug.txt";
var testIPNKey = "the hash here";
byte[] ipnToByes = Encoding.ASCII.GetBytes(testIPNKey); // IPN string to byteto hash with
var recvdIPN = Request["HTTP_IPN_HASH"];
HMACSHA256 testHash = new HMACSHA256(ipnToByes); // Setting testHash to IPN secret string
string ipnHeader = Request["IPN_HASH"];
using (StreamWriter sw = new StreamWriter(ipnDebugLog))
{
sw.WriteLine(ipnHeader);
foreach (var reqHead in ipnHeader)
{
sw.WriteLine(reqHead.ToString());
sw.WriteLine("JSON String: " + Request["HTTP_IPN_SECRET"]);
sw.WriteLine(recvdIPN);
sw.WriteLine("From: " + GetIPAddress());
}
}
}
So this is just me trying to get the data being sent from Rocketr. On the site it states:
To verify the integrity of the payload, we will send an HMAC signature
over a HTTP header called “IPN_HASH”. The HMAC signature will be a
signed json encoded POST object with your IPN secret. You can see how
to verify the signature in the example_rocketr_ipn.php file in this
repository.
Am i just to dumb and new to understand C# to function like this? I feel like i'm on the right track to reading the raw data but i'm probly wrong?
So to sum up the question
Am i doing the incorrect way to read a raw custom HTTP header called IPN_HASH? Going off of the PHP example they used isset to read a server variable header labled HTTP_IPN_HASH right?
So i have to convert this $hmac = hash_hmac("sha512", json_encode($_POST), trim($IPN_SECRET));
Try this (make adjustments as needed/necessary):
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
namespace Foo
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void PhpHashTest()
{
string IPN_SECRET = "I-am-the-secret";
//Mocking some HTTP POSTed data
var someFormUrlEncodedData = "order_id=1234&product_title=Hello%20World&product_id=Sku123";
//Mocking json_encode($_POST)
var data = HttpUtility.ParseQueryString(someFormUrlEncodedData);
var dictionary = data.AllKeys.ToDictionary(key => key, key => data[key]);
//{"order_id":"1234","product_title":"Hello World","product_id":"Sku123"}
var json = JsonConvert.SerializeObject(dictionary);
byte[] bytes;
using (var hmac512 = new HMACSHA512(Encoding.ASCII.GetBytes(IPN_SECRET)))
{
bytes = hmac512.ComputeHash(Encoding.ASCII.GetBytes(json));
}
//will contain lower-case hex like Php hash_hmac
var hash = new StringBuilder();
Array.ForEach(bytes, b => hash.Append(b.ToString("x2")));
//Assert that Php output exactly matches implementation
Assert.IsTrue(string.Equals("340c0049bde54aa0d34ea180f8e015c96edfc4d4a6cbd7f139d80df9669237c3d564f10366f3549a61871779c2a20d2512c364ee56af18a25f70b89bd8b07421", hash.ToString(), StringComparison.Ordinal));
Console.WriteLine(hash);
}
}
}
Not a PHP dev - this is my "Php version":
<?php
$IPN_SECRET = 'I-am-the-secret';
# 'order_id=1234&product_title=Hello%20World&product_id=Sku123';
$json = array('order_id' => '1234', 'product_title' => 'Hello World', 'product_id' =>'Sku123');
echo json_encode($json);
echo "<br />";
$hmac = hash_hmac("sha512", json_encode($json), trim($IPN_SECRET));
echo $hmac;
?>
Hth....
We need to work on .net based web application that will upload files to Amazon S3 Storage bucket using admin panel of the app and clients will be given to downloadable files with client.aspx file.
We looked at few example and got confused with some of the sample code for downloading non public files from S3 storage. one such example is below
AmazonS3Config config = new AmazonS3Config()
{
RegionEndpoint = RegionEndpoint.USEast1
};
IAmazonS3 client = new AmazonS3Client(accessKey, secretKey, config);
string dest = System.IO.Path.GetTempPath() + "event.mp4";
using (client)
{
GetObjectRequest request = new GetObjectRequest() { BucketName = "bucketname" + #"/" + "videos2015", Key = "event.mp4" };
using (GetObjectResponse response = client.GetObject(request))
{
response.WriteResponseStreamToFile(dest);
}
}
Response.Clear();
Response.AppendHeader("content-disposition", "attachment; filename=" + "dynamic_filename.png");
Response.ContentType = "application/octet-stream";
Response.TransmitFile(dest);
Response.Flush();
Response.End();
When user click on the link following code gets executed on web server and code downloads file on the web server and then serves the same file to client... if i am not wrong. Is there not a way that we can serve file for download directly from the AWS S3 storage.
In above case it is waste of server resources and increases the download time also.
Out files on AWS are not Public they are non public so the url is not accessible directly from client browsers as is in case of public content type
The pre-signed urls are indeed what you are looking for. Since you are using C#, here is a link to some useful code examples:
http://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLDotNetSDK.html
There is no need to upload files to s3 thru your webserver, they can be sent directly. Same thing on the download, download directly from S3 - don't copy them to EC2 first, you would be wasting bandwidth and processing resources.
You can use Minio-dotnet client library Its Open Source & supports compatible S3 API.
Here is an example for PresignedPostPolicy
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Minio;
namespace Minio.Examples
{
class PresignedPostPolicy
{
static int Main()
{
/// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY, my-bucketname and
/// my-objectname are dummy values, please replace them with original values.
var client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY");
PostPolicy form = new PostPolicy();
DateTime expiration = DateTime.UtcNow;
form.SetExpires(expiration.AddDays(10));
form.SetKey("my-objectname");
form.SetBucket("my-bucketname");
Dictionary <string, string> formData = client.PresignedPostPolicy(form);
string curlCommand = "curl ";
foreach (KeyValuePair<string, string> pair in formData)
{
curlCommand = curlCommand + " -F " + pair.Key + "=" + pair.Value;
}
curlCommand = curlCommand + " -F file=#/etc/bashrc https://s3.amazonaws.com/my-bucketname";
Console.Out.WriteLine(curlCommand);
return 0;
}
}
}
And below one for PresignedPutObject
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Minio;
namespace Minio.Examples
{
class PresignedPutObject
{
static int Main()
{
/// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY, my-bucketname and
/// my-objectname are dummy values, please replace them with original values.
var client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY");
Console.Out.WriteLine(client.PresignedPutObject("my-bucketname", "my-objectname", 1000));
return 0;
}
}
}
Hope it helps.
PS: I work for Minio
I am writing a c# mechanism to upload a file to a Rails server, using Json.
Before getting to the file part, i am just trying to post to the server, and seem to be having some problems with the json string that is arriving at the server..
What might I be doing wrong ? I already tried two different ways of serializing the string, and even loading an already serialized string...
I wonder if it has anything to do with the double quotes both at beginning and end of the string apparently being sent to server, and how to remove them from the request (without the surrounding quotes and using RestClient from WizTools.org, it all goes fine...) :
MultiJson::DecodeError (757: unexpected token at '"{\"receipt\":{\"total\":100.0,\"tag_number\":\"xxxxx\",\"ispaperduplicate\":true},\"machine\":{\"serial_number\":\"111111\",\"safe_token\":\"1Y321a\"}}"')
My c# code:
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 Newtonsoft.Json;
namespace RonRestClient
{
class templateRequest
{
public Receipt receipt;
public class Receipt
{
public float total;
public String tag_number;
public bool ispaperduplicate = true;
public Receipt(float total, String tagnr)
{
this.total = total;
this.tag_number = tagnr;
}
};
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:\file.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);
req.machine = new templateRequest.Machine(machinenr, safe_token);
//string json_body = JsonConvert.SerializeObject(req);
//string json_body = new JavaScriptSerializer().Serialize(req);
string 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");
var request = new RestRequest("/receipts",Method.POST);
//set request Body
request.AddHeader("Content-type", "application/json");
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
request.AddBody(json_body);
//request.AddParameter("text/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;
}
}
}
The problem is that the RestRequest.AddBody (source code) method actually presupposes that the content is not serialized to the correct format.
Meaning that it thinks that you are trying to pass the .NET string as a JSON string, instead of recognizing that you actually want to pass that string as a JSON object.
However, that means that you are actually doing too much work, by serializing the object to JSON yourself:
Replace line
request.AddBody(json_body);
with:
request.AddBody(req);
You can control the way that the serialization to JSON is done with the RestRequest.JsonSerializer property.
If you absolutely want to hold a JSON string, then I guess you might want to write:
request.AddParameter("application/json", json_body, ParameterType.RequestBody);
(I see that you have a line which is commented that practically does that - why did you comment it?)