Retrieving the Request Payload values from a HTTPRequest in c# - c#

I am attempting to implement my own LRS for saving TinCanAPI statements and in order to do this I need to retrieve the values sent in the Request Payload which stores the details of the learning activity statement.
When viewing my WebAPI call in developer tools I can see the required values but I have been unable to find them using the Request object.
How Can I retrieve the Request Payload variables from the Request object? I have tried the request object and looked in the Content and Properties fields but I cannot seem to see a Request Payload property to reference in C#. My payload looks as follows:
{
"id": "d3d9aa2a-5f20-4303-84c3-1f6f5b4e9236",
"timestamp": "2014-06-26T11:00:41.432Z",
"actor": {
"objectType": "Agent",
"mbox": "mailto:name#company.com",
"name": "My Name"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/attempted",
"display": {
"und": "attempted"
}
},
"context": {
"extensions": {
"http://tincanapi.com/JsTetris_TCAPI/gameId": "5686f104-3301-459d-9487-f84af3b3915c"
},
"contextActivities": {
"grouping": [
{
"id": "http://tincanapi.com/JsTetris_TCAPI",
"objectType": "Activity"
}
]
}
},
"object": {
"id": "http://tincanapi.com/JsTetris_TCAPI",
"objectType": "Activity",
"definition": {
"type": "http://adlnet.gov/expapi/activities/media",
"name": {
"en-US": "Js Tetris - Tin Can Prototype"
},
"description": {
"en-US": "A game of tetris."
}
}
}
}
I have tried using:
var test1 = Request.ToString(); **EMPTY STRING**
var test1 = Request.Content.ReadAsStringAsync().Result; **EMPTY STRING**
var test2 = Request.Content.ReadAsFormDataAsync().Result; **THROWS FORMATTER ERROR DESPITE config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); added in the webapiconfig.cs

I was able to retrieve the sent statement values by changing my WebAPI controller as follows:
public void Put([FromBody]TinCan.Statement statement)
{
var actor = statement.actor;
var context = statement.context;
var target = statement.target;
var timestamp = statement.timestamp;
var verb = statement.verb;
...................

try {
//String payloadRequest = getBody(request);
// System.out.println("payloadRequest : "+payloadRequest);
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String data = buffer.toString();
System.out.println("payloadRequest : "+data);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

Try this:
var value = Request["var_name"];

Related

How to get proper http status codes from Amazon API gateway integrated with C# lambda (not proxy integration)?

I am using a C# lambda to integrate with API gateway. I want API gateway to return proper error codes like 400, 404, 500 etc.
API gateway module tf file
provider "aws" {
version = "<= 2.70.0"
region = "${var.aws_region}"
profile = "${var.aws_profile}"
}
terraform {
# The configuration for this backend will be filled in by Terragrunt
backend "s3" {}
}
data "terraform_remote_state" "api_state" {
backend = "s3"
config {
region = "${var.aws_region}"
profile = "${var.aws_profile}"
bucket = "${var.s3_remote_state_bucket_name}"
key = "${var.s3_remote_state_key_name_api}"
}
}
data "terraform_remote_state" "resource_state"{
backend = "s3"
config {
region = "${var.aws_region}"
profile = "${var.aws_profile}"
bucket = "${var.s3_remote_state_bucket_name}"
key = "${var.s3_remote_state_key_name_resource}"
}
}
data "terraform_remote_state" "lambda_alias"{
backend = "s3"
config {
region = "${var.aws_region}"
profile = "${var.aws_profile}"
bucket = "${var.s3_remote_state_bucket_name}"
key = "${var.s3_remote_state_key_name_lambda}"
}
}
resource "aws_api_gateway_method" "http-method" {
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
http_method = "GET"
authorization = "CUSTOM"
authorizer_id = "${data.terraform_remote_state.api_state.Authorizers[var.Authorizer]}"
request_parameters = "${var.api_request_params_required}"
}
resource "aws_api_gateway_integration" "integration_GET" {
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
http_method = "${aws_api_gateway_method.http-method.http_method}"
integration_http_method = "POST"
type = "AWS"
uri = "arn:aws:apigateway:${var.aws_region}:lambda:path/2015-03-31/functions/${data.terraform_remote_state.lambda_alias.alias_lambda_arn}/invocations"
passthrough_behavior = "WHEN_NO_TEMPLATES"
request_templates = {
"application/json" = "${file("api_gateway_body_mapping.template")}"
}
}
resource "aws_api_gateway_model" "error_response" {
rest_api_id = "${aws_api_gateway_rest_api.api_gateway_rest_api.id}"
name = "ErrorResponse"
description = "The error respone object for all endpoints"
content_type = "application/json"
schema = <<EOF
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type" : "object",
"properties": {
"body": {
"type": "string"
},
"statusCode" : {
"type": "number"
}
}
}
EOF
}
resource "aws_api_gateway_method_response" "method_response" {
depends_on = ["aws_api_gateway_method.http-method"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "200"
}
resource "aws_api_gateway_method_response" "method_bad_request" {
depends_on = ["aws_api_gateway_method.http-method"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "400"
response_models {
"application/json" = "${aws_api_gateway_model.error_response}"
}
}
resource "aws_api_gateway_method_response" "method_not_found" {
depends_on = ["aws_api_gateway_method.http-method"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "404"
response_models {
"application/json" = "${aws_api_gateway_model.error_response}"
}
}
resource "aws_api_gateway_method_response" "method_error" {
depends_on = ["aws_api_gateway_method.http-method"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "500"
response_models {
"application/json" = "${aws_api_gateway_model.error_response}"
}
}
resource "aws_api_gateway_integration_response" "get_integration_response_success" {
depends_on = ["aws_api_gateway_method_response.method_response", "aws_api_gateway_integration.integration_GET"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "${aws_api_gateway_method_response.method_response.status_code}"
response_templates {
"application/json" = ""
}
}
resource "aws_api_gateway_integration_response" "get_integration_response_error" {
depends_on = ["aws_api_gateway_method_response.method_error", "aws_api_gateway_integration.integration_GET"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "${aws_api_gateway_method_response.method_error.status_code}"
selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?500.*"
response_templates {
"application/json"="${file("api_gateway_exception_mapping.template")}"
}
}
resource "aws_api_gateway_integration_response" "get_integration_response_bad_request" {
depends_on = ["aws_api_gateway_method_response.method_bad_request", "aws_api_gateway_integration.integration_GET"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "${aws_api_gateway_method_response.method_bad_request.status_code}"
selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?400.*"
response_templates {
"application/json"="${file("api_gateway_exception_mapping.template")}"
}
}
resource "aws_api_gateway_integration_response" "get_integration_response_not_found" {
depends_on = ["aws_api_gateway_method_response.method_not_found", "aws_api_gateway_integration.integration_GET"]
http_method = "${aws_api_gateway_method.http-method.http_method}"
resource_id = "${data.terraform_remote_state.resource_state.api_resource_id}"
rest_api_id = "${data.terraform_remote_state.api_state.api_gateway_rest_api_id}"
status_code = "${aws_api_gateway_method_response.method_not_found.status_code}"
selection_pattern = ".*statusCode['\"]\\s*:\\s*['\"]?404.*"
response_templates {
"application/json"="{}"
}
}
api_gateway_exception_mapping.template:
#set($inputRoot = $util.parseJson($input.path('$.errorMessage')))
{
"Error":"$inputRoot.body"
}
The integration response mapping is as in below snapshot
We have create APIs with lambda integration in python where I threw a custom APIException as below and it worked.
class ApiException(Exception):
"""Our custom APIException class which derives from the built-in Exception class"""
def __init__(self, status_code, message: str, **kwargs):
self.status_code = status_code
self.message = message
kwargs["statusCode"] = status_code
kwargs["body"] = message
super().__init__(json.dumps(kwargs))
Inside the lambda handler:
from .utils import ApiException
def lambda_handler(event, context):
try:
"""
CODE FOR LAMBDA HANDLER
"""
except Exception:
ex = ApiException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
message='Internal Error')
print("exception string: %s", ex)
raise ApiException(
status_code=500,
message='Internal server error')
When I logged the exception, I got the following output
{
"statusCode": 500,
"body": "Internal Server Error"
}
I also referred this stackoverflow answer on how to get proper error codes in API Gateway response. I modified that a little bit to throw an exception instead of just returning a json with statusCode, response body and headers as I am not using AWS_PROXY integration type
APIException.cs
public class APIException : Exception
{
public int statusCode;
public string body;
public APIException() : base() {}
public APIException(int statusCode, string message): base(message) {
this.statusCode = statusCode;
JObject json = JObject.Parse(message);
this.body = json["body"].ToString();
}
}
Lambda handler:
namespace LambdaFunction
{
public class Function
{
public async Task<JObject> FunctionHandler(JObject events, ILambdaContext context)
{
try
{
ValidateQueryParams(events, context);
JObject response = JObject.Parse(#"{
'mesage': 'success',
}");
return response;
}
catch(HttpListenerException ex)
{
string err = (new JObject(
new JProperty("statusCode", ex.ErrorCode),
new JProperty("body", ex.Message)
)).ToString();
return new APIException(ex.ErrorCode, err);
}
catch(Exception ex)
{
int err_code = (int)HttpStatusCode.InternalServerError
string err = (new JObject(
new JProperty("statusCode", err_code),
new JProperty("body", "Internal Server Error")
)).ToString();
var err_ex = new APIException(err_code, err);
context.Logger.LogLine("Unhandled exception occurred: " + ex.ToString());
return err_ex;
}
}
}
}
I've logged the exception before throwing it to see what we are getting and this is what I got
{
"statusCode": 500,
"body": "Internal Server Error",
"StackTrace": null,
"Message": "{\n \"statusCode\": 500,\n \"body\": \"Internal Server Error\"\n}",
"Data": {},
"InnerException": null,
"HelpLink": null,
"Source": null,
"HResult": -2146233088
}
But with the above code, I'm still just getting response code as 200 with below response body
{
"errorType": "APIException",
"errorMessage": "{\n \"statusCode\": 500,\n \"body\": \"Internal Server Error\"\n}",
"stackTrace": [
"..."
]
}
I am not sure where I am going wrong. Any help will be appreciated. Thanks.
I've figured out the issue. C#'s .ToString() function which converts JObject into a string is formatting the string and adding new line characters \n by default. But the regex used in API gateway to identify error codes does not consider new line characters. The fix was pretty simple. We need to tell the .ToString() function that it shouldn't do any formatting. So, instead of
new JObject(
new JProperty("statusCode", err_code),
new JProperty("body", "Internal Server Error")
)).ToString();
You need to do
new JObject(
new JProperty("statusCode", err_code),
new JProperty("body", "Internal Server Error")
)).ToString(Formatting.None);
And it worked.

Deserializing JsonArray

I've written a code which calls an API which returns a Json Array which I have tired to deserialize using Json.net as below-
static async void MakeAnalysisRequest(string imageFilePath)
{
HttpClient client = new HttpClient();
// Request headers.
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
// Request parameters. A third optional parameter is "details".
string requestParameters = "returnFaceId=true";
// Assemble the URI for the REST API Call.
string uri = uriBase + "?" + requestParameters;
HttpResponseMessage response;
// Request body. Posts a locally stored JPEG image.
byte[] byteData = GetImageAsByteArray(imageFilePath);
using (ByteArrayContent content = new ByteArrayContent(byteData))
{
// This example uses content type "application/octet-stream".
// The other content types you can use are "application/json" and "multipart/form-data".
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// Execute the REST API call.
response = await client.PostAsync(uri, content);
// Get the JSON response.
string contentString = await response.Content.ReadAsStringAsync();
// Display the JSON response.
Console.WriteLine("\nResponse:\n");
List<Facejson> obj=JsonConvert.DeserializeObject<List<Facejson>>(contentString);
Console.WriteLine(obj[0].Face.faceId);
}
}
public class Facejson
{
[JsonProperty("face")]
public Face Face { get; set; }
}
public class Face
{
[JsonProperty("faceId")]
public string faceId { get; set; }
}
The Api response Json is in the format
[
{
"faceId": "f7eda569-4603-44b4-8add-cd73c6dec644",
"faceRectangle": {
"top": 131,
"left": 177,
"width": 162,
"height": 162
}
},
{
"faceId": "f7eda569-4603-44b4-8add-cd73c6dec644",
"faceRectangle": {
"top": 131,
"left": 177,
"width": 162,
"height": 162
}
}
]
When I compile my code, the following error shows up
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
in the line
Console.WriteLine(obj[0].Face.faceId);
I have declared the method "Face" but it shows that I have not. What am I doing wrong?
Edit- fixed Json and faulty code fixed as suggested.
You are deserializing a List<Face>, so to access one item on this list, you will have to use an index:
Console.WriteLine( obj[0].Face.faceId );
Or enumerate all results one-by-one:
foreach ( var face in obj )
{
Console.WriteLine( face.Face.faceId );
}
Update
You are deserializing a wrong type. Your JSON is directly a list of Face class instances, so the FaceJson type is not necessary:
List<Face> obj = JsonConvert.DeserializeObject<List<Face>>(contentString);
foreach ( var face in obj )
{
Console.WriteLine( face.faceId );
}
JSON string you shared is not correct. Please check this fiddle.
[
{
"faceId": "f7eda569-4603-44b4-8add-cd73c6dec644",
"faceRectangle": {
"top": 131,
"left": 177,
"width": 162,
"height": 162
}
},
{
"faceId": "f7eda569-4603-44b4-8add-cd73c6dec644",
"faceRectangle": {
"top": 131,
"left": 177,
"width": 162,
"height": 162
}
}
]
Also you are deserializing a List<Face> , you can access it using index only.
UPDATE
You need to deserialize List<Face> not single Face class. It will solve you problem.

Fire TriggeredSends from ExactTarget's API using HttpClient REST

I've read along the way that Salesforce (I'm extremely new to this 3rd party platform) has a FUEL SDK which one can use instead of the version (using HttpClient -- REST instead of SOAP).
Please correct me if using FUEL SDK is the only way to go about requesting Salesforce's endpoints. Currently I am attempting to hit ExactTargets's API endpoints using HttpClient. These are the tutorials I've been basing my code off of:
https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/messageDefinitionSends.htm
https://developer.salesforce.com/docs/atlas.en-us.mc-getting-started.meta/mc-getting-started/get-access-token.htm
Wanted Result:
To be able to request a Triggered Send email based off a template inside of ExactTarget.
Problem:
The Salesforce endpoint continuously returns a 404. I am able to receive the authorization token successfully. The GetAccessToken method is omitted for brevity
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
I do not understand why the 2nd POST request to //www.exacttargetapis.com/..... returns a 404 but the authorization works. This leads me to believe that I do not have to use the FUEL SDK to accomplish triggering a welcome email.
Code:
private const string requestTokenUrl = "https://auth.exacttargetapis.com/v1/requestToken";
private const string messagingSendUrl = "https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends";
private string exactTargetClientId = ConfigurationManager.AppSettings["ExactTargetClientId"];
private string exactTargetClientSecret = ConfigurationManager.AppSettings["ExactTargetClientSecret"];
private string TriggerEmail(User model, string dbName)
{
var etExternalKeyAppSetting = ConfigurationManager.AppSettings.AllKeys.FirstOrDefault(x => x.Equals(dbName));
if (etExternalKeyAppSetting != null)
{
string etExternalKey = ConfigurationManager.AppSettings[etExternalKeyAppSetting];
HttpClient client = new HttpClient
{
BaseAddress = new Uri(string.Format(#"{0}/key:{1}/send", messagingSendUrl, etExternalKey)),
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue("Bearer", this.GetAccessToken())
}
};
try
{
var postData = this.CreateExactTargetPostData(model.Email, etExternalKey);
var response = client.PostAsync(client.BaseAddress
, new StringContent(JsonConvert.SerializeObject(postData).ToString()
, Encoding.UTF8
, "application/json")).Result;
// get triggered email response
if (response.IsSuccessStatusCode)
{
dynamic result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
string message = ex.Message;
}
}
return "testing";
}
private object CreateExactTargetPostData(string email, string extKey)
{
var fromData = new
{
Address = ConfigurationManager.AppSettings["AwsSenderEmail"],
Name = "Test"
};
var subscriberAttributes = new { };
var contactAttributes = new
{
SubscriberAttributes = subscriberAttributes
};
var toData = new
{
Address = email,
//SubscriberKey = extKey,
//ContactAttributes = contactAttributes
};
var postData = new
{
From = fromData,
To = toData
};
return postData;
}
I have also tried using Advanced REST Client using the following:
URL:
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
POST
Raw Headers:
Content-Type: application/json
Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Raw Payload:
{
"From": {
"Address": "code#exacttarget.com",
"Name": "Code#"
},
"To": {
"Address": "example#example.com",
"SubscriberKey": "example#example.com",
"ContactAttributes": {
"SubscriberAttributes": {
"Region": "West",
"City": "Indianapolis",
"State": "IN"
}
}
},
"OPTIONS": {
"RequestType": "ASYNC"
}
}
Issue was my App in the AppCenter was pointing to the incorrect login for MarketingCloud =(

S3 - policy and signed policy

I dont understand what is wrong((
And I have a few questions:
1) If I must put any policy to my S3 bucket. If yes - can you help me understand how to create a policy
2) I have this policy:
{
"expiration": "2016-11-07T20:18:13.326Z",
"conditions": [
{
"acl": "public"
},
{
"bucket": "bucket_name"
},
{
"Content-Type": "text/plain"
},
{
"success_action_status": "200"
},
{
"key": "c94d36ee-19eb-49e8-ac30-760b29982391.txt"
},
{
"x-amz-meta-qqfilename": "111.txt"
}
]
}
So in my C# code I do :
private string GeneratePolicy()
{
byte[] bytesToEncode = File.ReadAllBytes("s3policy.txt");
string encodedText = Convert.ToBase64String(bytesToEncode);
return encodedText;
}
static string GetSig(string policyStr)
{
string b64Policy = Convert.ToBase64String(Encoding.ASCII.GetBytes(policyStr));
byte[] b64Key = Encoding.ASCII.GetBytes("HERE-IS-MY-SECRET-KEY");
HMACSHA1 hmacSha1 = new HMACSHA1(b64Key);
string singPolicy = Convert.ToBase64String(hmacSha1.ComputeHash(Encoding.ASCII.GetBytes(b64Policy)));
return singPolicy;
}
But is doesn't work (
Any idea why?
Thank you

Error in Set and Unset watermark Request using Youtube Data API V3

I am using
IDE : VS2012
Framework : 4.0
Google API: Youtube Data V3
Authentication: Outh 2.0
I am using Youtube Data API V3 to set watermark on youtube video . Here is my code
**my fiddler request** is : POST https://www.googleapis.com/youtube/v3/watermarks/set?channelId=UCyAn2aVZWNAugdlckOJKG5A
and my content body :
{
"position": {
"cornerPosition": "topRight",
"type": "corner"
},
"timing": {
"durationMs": "50000",
"offsetMs": "1000",
"type": "offsetFromStart"
},
"targetChannelId": "UCyAn2aVZWNAugdlckOJKG5A"
}
i am passing image content with stream object with set method ..
and Response is: Value cannot be null Parameter name: baseUri
public async Task setwatermark()
{
InvideoBranding ib = new InvideoBranding();
InvideoTiming it = new InvideoTiming();
InvideoPosition ip = new InvideoPosition();
Stream stream = null;
it.Type = "offsetFromStart";
it.OffsetMs = 1000;
it.DurationMs = 50000;
ip.Type = "corner";
ip.CornerPosition = "topRight";
string filepath = Server.MapPath("~/Images/orderedList0.png");
ib.TargetChannelId = "UCyAn2aVZWNAugdlckOJKG5A";
// ib.ImageUrl = filepath;
ib.Position = ip;
ib.Timing = it;
using (var fileStream = new FileStream(filepath, FileMode.Open))
{
stream = (Stream)fileStream;
var setrequest = youtubeService.Watermarks.Set(ib, "UCyAn2aVZWNAugdlckOJKG5A",stream,"image/*");
var resp =await setrequest.UploadAsync();
}
Below code is for unset watermarks using YouTube Data API V3.
It is response with --Error 503-backend error.
Fiddler Request :POST https://www.googleapis.com/youtube/v3/watermarks/unset?channelId=UCyAn2aVZWNAugdlckOJKG5A
**Fiddler response** :{
"error": {
"errors": [
{
"domain": "global",
"reason": "back end Error",
"message": "Back end Error"
}
],
"code": 503,
"message": "Back end Error"
}
}
private void Unsetwatermark()
{
var unsetrequest = youtubeService.Watermarks.Unset("UCyAn2aVZWNAugdlckOJKG5A");
var searchListResponse = unsetrequest.Execute();
}
Please tell me what i am doing wrong for both above mentioned api request ..

Categories