Getting declined (2046: Transaction Refused) from Paypal Sandbox transaction - c#

I'm using Braintree SDK in .NET. Implemented the SDK and followed the documentation.
Created Sandbox Merchant Account
Created Sandbox Personal Account
I'm using the Access Token for the transaction. Please refer the following code snippet:
//--------------------------- Get Token for client ---------------------------
public PaypalHelper.Paypal_ResponseObj<string> GetPaypalClientToken()
{
string PaypalAccessToken = "XXXXXXXXXXXXXXXXXXX";
if (PaypalAccessToken != null)
{
BraintreeGateway gateway = new BraintreeGateway(PaypalAccessToken);
string clientToken = gateway.ClientToken.Generate();
return new PaypalHelper.Paypal_ResponseObj<string>()
{
Code = HttpStatusCode.OK,
Message = "Payment from paypal successfully initiated.",
Response = clientToken
};
}
else
{
return new PaypalHelper.Paypal_ResponseObj<string>()
{
Code = HttpStatusCode.Unauthorized,
Message = "Unauthorized! Paypal access token is not set or invalid.",
Response = null
};
}
}
//--------------------------- Do Paypal transaction ---------------------------
public PaypalHelper.Paypal_ResponseObj<Result<Transaction>> PayPalTransaction(string Nonce, decimal Amount)
{
if (!string.IsNullOrEmpty(Nonce) && !string.IsNullOrWhiteSpace(Nonce) && Amount > 0)
{
string PaypalAccessToken = "XXXXXXXXXXXXXXXXXXX";
if (PaypalAccessToken != null)
{
BraintreeGateway gateway = new BraintreeGateway(PaypalAccessToken);
var request = new TransactionRequest
{
Amount = Amount,
PaymentMethodNonce = Nonce,
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};
var result = gateway.Transaction.Sale(request);
if (result.IsSuccess())
{
if (result.Errors == null && result.Target != null)
{
return new PaypalHelper.Paypal_ResponseObj<Result<Transaction>>()
{
Code = HttpStatusCode.OK,
Message = "Payment from paypal successfully initiated.",
Response = result
};
}
else
{
return new PaypalHelper.Paypal_ResponseObj<Result<Transaction>>()
{
Code = HttpStatusCode.Conflict,
Message = "Unable to process this request.",
Response = result
};
}
}
else
{
return new PaypalHelper.Paypal_ResponseObj<Result<Transaction>>()
{
Code = HttpStatusCode.Conflict,
Message = "Payment unsuccessfull.",
Response = result
};
}
}
else
{
return new PaypalHelper.Paypal_ResponseObj<Result<Transaction>>()
{
Code = HttpStatusCode.Unauthorized,
Message = "Un authorized! Paypal access token is not set or invalid.",
Response = null
};
}
}
else {
return new PaypalHelper.Paypal_ResponseObj<Result<Transaction>>()
{
Code = HttpStatusCode.BadRequest,
Message = "input can't be null!",
Response = null
};
}
}
Just to summarize all, we have a PayPal business account and we also created a Sandbox business merchant account and Sandbox personal account to test this scenario.
Please refer the following payload being sent to PayPal for the transaction:
{
"CreditCard":null,
"Amount":235.0000,
"DeviceData":null,
"DeviceSessionId":null,
"FraudMerchantId":null,
"Channel":null,
"OrderId":"SWS-O-RQ-894XX",
"Recurring":null,
"TransactionSource":null,
"MerchantAccountId":"USD",
"PurchaseOrderNumber":null,
"Customer":{
"Id":null,
"DeviceData":null,
"CustomerId":null,
"FirstName":"John",
"LastName":"Doe",
"Company":null,
"Email":"johndoe#swsn.com",
"Phone":"330459218319",
"Fax":null,
"Website":null,
"PaymentMethodNonce":null,
"DefaultPaymentMethodToken":null,
"CustomFields":null,
"CreditCard":null,
"UsBankAccount":null,
"RiskData":null,
"Options":null
},
"Descriptor":null,
"Industry":null,
"BillingAddress":null,
"ShippingAddress":{
"FirstName":"John",
"LastName":"Doe",
"Company":null,
"StreetAddress":"XX Boulevard Haussmann",
"ExtendedAddress":null,
"Locality":"Paris",
"Region":null,
"PostalCode":"75008",
"CountryCodeAlpha2":"FR",
"CountryCodeAlpha3":null,
"CountryCodeNumeric":null,
"CountryName":null
},
"PayPalAccount":null,
"TaxAmount":null,
"TaxExempt":null,
"Type":null,
"CustomFields":{
},
"Options":{
"HoldInEscrow":null,
"StoreInVault":null,
"StoreInVaultOnSuccess":null,
"AddBillingAddressToPaymentMethod":null,
"StoreShippingAddressInVault":null,
"SubmitForSettlement":true,
"VenmoSdkSession":null,
"PayeeId":null,
"PayeeEmail":null,
"SkipAdvancedFraudChecking":null,
"SkipAvs":null,
"SkipCvv":null,
"PayPal":null,
"ThreeDSecure":null,
"AmexRewards":null,
"Venmo":null,
"CreditCard":null
},
"ThreeDSecurePassThru":null,
"PaymentMethodToken":null,
"CustomerId":null,
"ShippingAddressId":null,
"BillingAddressId":null,
"VenmoSdkPaymentMethodCode":null,
"PaymentMethodNonce":"799178b2-1e00-0ac7-6db0-034a9a668b1a",
"ServiceFeeAmount":null,
"SharedPaymentMethodToken":null,
"SharedPaymentMethodNonce":null,
"SharedCustomerId":null,
"SharedShippingAddressId":null,
"SharedBillingAddressId":null,
"ThreeDSecureToken":null,
"RiskData":null,
"DiscountAmount":null,
"ShippingAmount":null,
"ShipsFromPostalCode":null,
"LineItems":null,
"ExternalVault":null
}
Please refer the following response object that we are getting from PayPal after initiating a transaction:
{
"CreditCardVerification":null,
"Transaction":{
"Id":"r9b19cwh",
"AddOns":[
],
"Amount":235,
"AvsErrorResponseCode":null,
"AvsPostalCodeResponseCode":"I",
"AvsStreetAddressResponseCode":"I",
"BillingAddress":{
"Id":null,
"CustomerId":null,
"FirstName":null,
"LastName":null,
"Company":null,
"StreetAddress":null,
"ExtendedAddress":null,
"Locality":null,
"Region":null,
"PostalCode":null,
"CountryCodeAlpha2":null,
"CountryCodeAlpha3":null,
"CountryCodeNumeric":null,
"CountryName":null,
"CreatedAt":null,
"UpdatedAt":null
},
"Channel":null,
"CreatedAt":"2020-03-31T19:25:43Z",
"CreditCard":{
"Bin":null,
"CardholderName":null,
"CardType":{
},
"CreatedAt":null,
"CustomerId":null,
"IsDefault":null,
"IsVenmoSdk":false,
"IsExpired":null,
"CustomerLocation":{
},
"LastFour":null,
"UniqueNumberIdentifier":null,
"Subscriptions":[
],
"Token":null,
"UpdatedAt":null,
"BillingAddress":{
"Id":null,
"CustomerId":null,
"FirstName":null,
"LastName":null,
"Company":null,
"StreetAddress":null,
"ExtendedAddress":null,
"Locality":null,
"Region":null,
"PostalCode":null,
"CountryCodeAlpha2":null,
"CountryCodeAlpha3":null,
"CountryCodeNumeric":null,
"CountryName":null,
"CreatedAt":null,
"UpdatedAt":null
},
"ExpirationMonth":null,
"ExpirationYear":null,
"Prepaid":{
},
"Payroll":{
},
"Debit":{
},
"Commercial":{
},
"Healthcare":{
},
"DurbinRegulated":{
},
"ImageUrl":"https://assets.braintreegateway.com/payment_method_logo/unknown.png?environment=sandbox",
"Verification":null,
"AccountType":null,
"CountryOfIssuance":"Unknown",
"IssuingBank":"Unknown",
"ProductId":"Unknown",
"ExpirationDate":"/",
"MaskedNumber":"**"
},
"CurrencyIsoCode":"USD",
"CustomerDetails":{
"Id":null,
"FirstName":"John",
"LastName":"Doe",
"Company":null,
"Email":"johndoe#swsln.com",
"Phone":"000459210000",
"Fax":null,
"Website":null
},
"CvvResponseCode":"I",
"Descriptor":{
"Name":null,
"Phone":null,
"Url":null
},
"Discounts":[
],
"Disputes":[
],
"GatewayRejectionReason":{
},
"MerchantAccountId":"USD",
"OrderId":"SWS-O-RQ-894XX",
"PlanId":null,
"ProcessorAuthorizationCode":null,
"ProcessorResponseType":{
},
"ProcessorResponseCode":"2046",
"ProcessorResponseText":"Declined",
"ProcessorSettlementResponseCode":null,
"ProcessorSettlementResponseText":null,
"AdditionalProcessorResponse":"2046 : TRANSACTION_REFUSED",
"VoiceReferralNumber":null,
"PurchaseOrderNumber":null,
"Recurring":false,
"RefundedTransactionId":null,
"RefundIds":[
],
"PartialSettlementTransactionIds":[
],
"AuthorizedTransactionId":null,
"SettlementBatchId":null,
"ShippingAddress":{
"Id":null,
"CustomerId":null,
"FirstName":"John",
"LastName":"Doe",
"Company":null,
"StreetAddress":"XX Boulevard XXXX",
"ExtendedAddress":null,
"Locality":"Paris",
"Region":null,
"PostalCode":"75008",
"CountryCodeAlpha2":"FR",
"CountryCodeAlpha3":"FRA",
"CountryCodeNumeric":"250",
"CountryName":"France",
"CreatedAt":null,
"UpdatedAt":null
},
"EscrowStatus":{
},
"Status":{
},
"StatusHistory":[
{
"Amount":235,
"Status":{
},
"Timestamp":"2020-03-31T19:25:48Z",
"Source":{
},
"User":null
}
],
"AuthorizationAdjustments":[
],
"SubscriptionId":null,
"SubscriptionDetails":{
"BillingPeriodEndDate":null,
"BillingPeriodStartDate":null
},
"TaxAmount":null,
"TaxExempt":false,
"Type":{
},
"UpdatedAt":"2020-03-31T19:25:48Z",
"CustomFields":{
},
"ServiceFeeAmount":null,
"DisbursementDetails":{
"SettlementAmount":null,
"SettlementCurrencyIsoCode":null,
"SettlementCurrencyExchangeRate":null,
"FundsHeld":null,
"Success":null,
"DisbursementDate":null
},
"ApplePayDetails":null,
"AndroidPayDetails":null,
"AmexExpressCheckoutDetails":null,
"PayPalDetails":{
"PayerEmail":"sb-zkd0t1338940#personal.example.com",
"PaymentId":null,
"AuthorizationId":null,
"Token":null,
"ImageUrl":"https://assets.braintreegateway.com/payment_method_logo/paypal.png?environment=sandbox",
"DebugId":"20ac958b09914",
"PayeeId":null,
"PayeeEmail":null,
"CustomField":null,
"PayerId":null,
"PayerFirstName":null,
"PayerLastName":null,
"PayerStatus":null,
"SellerProtectionStatus":null,
"CaptureId":null,
"RefundId":null,
"TransactionFeeAmount":null,
"TransactionFeeCurrencyIsoCode":null,
"RefundFromTransactionFeeAmount":null,
"RefundFromTransactionFeeCurrencyIsoCode":null,
"Description":null
},
"LocalPaymentDetails":null,
"CoinbaseDetails":null,
"VenmoAccountDetails":null,
"UsBankAccountDetails":null,
"IdealPaymentDetails":null,
"VisaCheckoutCardDetails":null,
"MasterpassCardDetails":null,
"SamsungPayCardDetails":null,
"PaymentInstrumentType":{
},
"RiskData":null,
"ThreeDSecureInfo":null,
"FacilitatedDetails":null,
"FacilitatorDetails":null,
"DiscountAmount":null,
"ShippingAmount":null,
"ShipsFromPostalCode":null,
"NetworkTransactionId":null,
"AuthorizationExpiresAt":null
},
"Subscription":null,
"Errors":{
"Count":0,
"DeepCount":0
},
"Parameters":{
"transaction[amount]":"235.00",
"transaction[order_id]":"SWS-O-RQ-894XX",
"transaction[payment_method_nonce]":"799178b2-1e00-0ac7-6db0-034a9a668bXX",
"transaction[merchant_account_id]":"USD",
"transaction[type]":"sale",
"transaction[customer][first_name]":"John",
"transaction[customer][last_name]":"Doe",
"transaction[customer][email]":"johndoe#swsln.com",
"transaction[customer][phone]":"330459218319",
"transaction[shipping][first_name]":"John",
"transaction[shipping][last_name]":"Doe",
"transaction[shipping][street_address]":"63 Boulevard Haussmann",
"transaction[shipping][locality]":"Paris",
"transaction[shipping][postal_code]":"75008",
"transaction[shipping][country_code_alpha2]":"FR",
"transaction[options][submit_for_settlement]":"true"
},
"Message":"Declined",
"Target":null
}
Anyone? who can help me to figure out this issue. Is there something I'm missing?

Related

Error while creating a WorkItem via API - Devops

I'm trying to create a workitem via API, but im getting the following error:
{
"innerException": null,
"message": "You must pass a valid patch document in the body of the request.",
"typeName": "Microsoft.VisualStudio.Services.Common.VssPropertyValidationException, Microsoft.VisualStudio.Services.Common",
"typeKey": "VssPropertyValidationException",
"errorCode": 0,
"eventId": 3000
}
Code:
public class Chamados
{
public async Task<string> CriaChamadoDevOps()
{
string organizacao = "xxx";
string departamento = "xxx";
string tipoWorkItem = "xxx";
string authToken = "xxx";
// Montando a Requisição
string urlReq = "https://dev.azure.com/" + organizacao + "/" + departamento + "/_apis/wit/workitems/$" + tipoWorkItem + "?api-version=6.0";
var client = new RestClient(urlReq);
var request = new RestRequest(urlReq, Method.Post);
// Montando Headers
request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", authToken))));
request.AddHeader("Content-Type", "application/json-patch+json; charset=utf-8");
var body = new JArray {
new JObject {
{ "op", "add" },
{ "path", "/fields/System.Title" },
{ "value", "Assunto Teste" }
},
new JObject {
{ "op", "add" },
{ "path", "/fields/System.State" },
{ "value", "To do" }
},
new JObject {
{ "op", "add" },
{ "path", "/fields/System.Description" },
{ "value", "Descricao Teste" }
},
};
//request.AddBody(body);
request.AddParameter("application/json-patch+json; charset=utf-8", body, ParameterType.RequestBody);
Console.WriteLine(body);
RestResponse response = await client.ExecuteAsync(request);
dynamic resposta = JsonConvert.DeserializeObject(response.Content);
return resposta.ToString();
}
}
When i test it via Postman, it works.
This is how im sending the body to the request:
(Output from Console.WriteLine(body);)
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Assunto Teste"
},
{
"op": "add",
"path": "/fields/System.State",
"value": "To do"
},
{
"op": "add",
"path": "/fields/System.Description",
"value": "Descricao Teste"
}
]
And i've also tried replacing the "request.AddParameter()" with "request.AddBody()" method.
Maybe you can start by reading the docs: https://restsharp.dev/usage.html#request-body
Then, you'd figure out that since you don't want to build strongly-typed request models and prefer using JObject, you need to handle the serialization yourself:
request.AddStringBody(body.ToString(), "application/json-patch+json");
and that the docs tell you not to add content-type as the request header as it's the content header, and AddStringBody will do it.

Unable to create a company in Intercom

I'm using this code:
Authentication authentication = new Authentication("myAccessToken");
RestClientFactory restClientFactory = new RestClientFactory(authentication);
var _companyClient = new CompanyClient(restClientFactory);
var companyCustomAttributes = new Dictionary<string, object>()
{
{ "name", "TradingName" },
{ "company_id_str", "5432" },
{ "isoCode", "AU" },
{ "regionCode", "VIC" },
{ "isPropertyManagement", false },
{ "isSales", false },
{ "setupComplete", false },
{ "isSubscription", false },
{ "subscriptionSetupComplete", false },
{ "tradingName", "TradingName" },
{ "ofSMS", false },
{ "ofBankTransfer", false },
{ "ofCommercial", false },
{ "isEmailValidated", true },
{ "isLocked", false },
{ "isOutgoingEmailValidated", true },
{ "banks", "" },
{ "earlyAdopterProgram", false },
{ "propertyCount", 0 }
};
var company = new Company();
company.company_id = "5432";
company.custom_attributes = companyCustomAttributes;
var createdCompany = _companyClient.Create(company);
The createdCompany is not null:
But the company is not showing in the UI:
Why is the company not showing in the UI?
Intercom API version = 1.4
Intercom.Dotnet.Client version = 2.1.1
Github issue submitted:
https://github.com/intercom/intercom-dotnet/issues/158
The company won't show up if there are no users attached to it.

Converting this code to use Microsoft Graph with batch mode

Here is my code for deleting a set of calendar entries:
public async Task<bool> DeleteCalendarEvents(SettingsBase oSettings)
{
try
{
var oEvents = await _graphClient
.Me
.Calendars[oSettings.CalendarID]
.Events
.Request()
.Select("Start,Subject,Id")
.Top(50)
.Filter(oSettings.GetFilterString())
.OrderBy("start/DateTime")
.GetAsync();
List<Event> listEvents = new List<Event>();
listEvents.AddRange(oEvents);
while (oEvents.NextPageRequest != null)
{
oEvents = await oEvents.NextPageRequest.GetAsync();
listEvents.AddRange(oEvents);
}
foreach (Event oEvent in listEvents)
{
await _graphClient.Me.Events[oEvent.Id].Request().DeleteAsync();
}
}
catch (Exception ex)
{
SimpleLog.Log(ex);
Console.WriteLine("DeleteCalendarEvents: See error log.");
return false;
}
return true;
}
I then have a method that adds new events into the calendar:
public async Task<bool> AddEventsToCalendar(MWBData.MWBCalendarData oData)
{
if (oData.SettingsMWB.CalendarEntryType != "CLM_MidweekMeeting")
{
SimpleLog.Log("AddEventsToCalendar: CalendarEntryType is not set to CLM_MidweekMeeting.", SimpleLog.Severity.Error);
Console.WriteLine("AddEventsToCalendar: See error log.");
return false;
}
try
{
// Now create the new events
foreach (EventWeek oWeek in oData.Weeks)
{
bool bSuccess = await AddEventToCalendar(oWeek, oData.SettingsMWB);
if(bSuccess)
{
// Now create any Weekend Meeting events
if(oWeek.WeekendMeeting.Included)
{
bSuccess = await AddEventToCalendar(oWeek.WeekendMeeting, oData.SettingsMWB);
if(!bSuccess)
{
Console.WriteLine("AddEventsToCalendar: See error log.");
return false;
}
}
}
else
{
Console.WriteLine("AddEventToCalendar: See error log.");
return false;
}
}
}
catch (Exception ex)
{
SimpleLog.Log(ex);
Console.WriteLine("AddEventsToCalendar: See error log.");
return false;
}
return true;
}
As you can see, for each event it calls AddEventToCalendar. That method, in part, creates the event like this:
// Add the event
Event createdEvent = await _graphClient.Me.Calendars[oSettings.CalendarID].Events.Request().AddAsync(new Event
{
Subject = oEvent.GetSubject(),
Body = body,
Start = startTime,
End = endTime,
IsAllDay = oEvent.IsAllDayEvent(),
IsReminderOn = bSetReminder,
ReminderMinutesBeforeStart = bSetReminder ? iReminderMinutes : (int?)null,
Location = location,
SingleValueExtendedProperties = extendedProperties,
Sensitivity = oSettings.SetCalendarPrivate ? Sensitivity.Private : Sensitivity.Normal
});
Now, I know that Microsoft Graph supports batch mode using JSON. But I am at a loss as to how to implement that with what I have written. It makes sense to try and convert my code into a list of batch operations to reduce the calls.
How do I do this?
Update
I have located this article but I am not sure if it is relevant and what I should do. So I would still appreciate any specific guidance with how to do this. I am sure that other potential users would benefit from this greatly - or be directed to an existing resource that I have missed. Thank you.
Even though batch request is not yet supported you could consider the following proof-of-concept that demonstrates how to implement a basic support for retrieving entities on top of msgraph-sdk-dotnet:
//1.Construct a Batch request
var batchRequest = new BatchRequest();
//2. Add sub queries. Two parameters needs to be specified: a request and a result object
batchRequest.AddQuery(graphClient.Users[loginName].Request(), typeof(Microsoft.Graph.User));
batchRequest.AddQuery(graphClient.Sites["root"].Request(),typeof(Microsoft.Graph.Site));
//3. Execute Batch request
var result = await graphClient.GetBatchAsync(batchRequest);
where BatchRequest class introduces a support for Batch request
public class BatchRequest
{
private Dictionary<string, IBaseRequest> _queriesTable = new Dictionary<string, IBaseRequest>();
private Dictionary<string,Type> _resultsTable = new Dictionary<string, Type>();
public KeyValuePair<IBaseRequest, Type> this[string queryId]
{
get
{
return new KeyValuePair<IBaseRequest,Type>(_queriesTable[queryId], _resultsTable[queryId]);
}
}
public void AddQuery(IBaseRequest query, Type entityType)
{
var queryId = Guid.NewGuid().ToString();
_resultsTable[queryId] = entityType;
_queriesTable[queryId] = query;
}
/// <summary>
/// Construct JSON batch request https://developer.microsoft.com/en-us/graph/docs/concepts/json_batching
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
public HttpRequestMessage ToMessage(GraphServiceClient client)
{
var batchMessage = new HttpRequestMessage();
batchMessage.RequestUri = new Uri("https://graph.microsoft.com/v1.0/$batch");
batchMessage.Method = HttpMethod.Post;
batchMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
dynamic payload = new ExpandoObject();
payload.requests = _queriesTable.Select(kv =>
{
var message = kv.Value.GetHttpRequestMessage();
dynamic request = new ExpandoObject();
request.id = kv.Key;
request.method = message.Method.ToString();
request.url = message.RequestUri.AbsoluteUri.Replace(client.BaseUrl,string.Empty);
if(message.Content != null)
request.body = message.Content;
request.headers = message.Headers.ToDictionary(x => x.Key, x => x.Value.FirstOrDefault());
return request;
});
var jsonPayload = client.HttpProvider.Serializer.SerializeObject(payload);
batchMessage.Content = new StringContent(jsonPayload,Encoding.UTF8,"application/json");
return batchMessage;
}
}
and GetBatchAsync is extension method to execute a batch request:
public static class GraphServiceClientExtensions
{
public static async Task<List<object>> GetBatchAsync(this GraphServiceClient client, BatchRequest request)
{
var batchMessage = request.ToMessage(client);
await client.AuthenticationProvider.AuthenticateRequestAsync(batchMessage);
var response = await client.HttpProvider.SendAsync(batchMessage);
var content = await response.Content.ReadAsStringAsync();
var json = JObject.Parse(content);
var entities = json["responses"].Select(item =>
{
var queryId = (string)item["id"];
var entityPayload = JsonConvert.SerializeObject(item["body"]);
var subRequest = request[queryId];
var entity = JsonConvert.DeserializeObject(entityPayload, subRequest.Value);
return entity;
});
return entities.ToList();
}
}
Gist: Microsoft.Graph.BatchSupport.cs
Like i said it is just a proof-of-concept and only retrieving of entities are supported in this implementation, so if you want to implement another operations like delete you could utilize it as a starting point
Results
This is not supported in the graph library now.
https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/136
A workaround for you, use HttpClient to request batch endpoint,
Mock jsonObject(You need to use StringBuilder or such to create the string, use for/foreach to iterate over the event list and then append item info to the json object, just remember to increment the id value):
Note: Nested json seems doesn't work on Graph, so this workground still need test.
{
"requests": [
{
"id": "1",
"url": "/me",
"method": "POST",
"body": {
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does late morning work for you?"
},
"start": {
"dateTime": "2017-04-15T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-15T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"samanthab#contoso.onmicrosoft.com",
"name": "Samantha Booth"
},
"type": "required"
}
]
},
"headers": {
"Content-Type": "application/json"
}
},
{
"id": "2",
"url": "/me",
"method": "POST",
"body": {
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does late morning work for you?"
},
"start": {
"dateTime": "2017-04-15T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-15T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"samanthab#contoso.onmicrosoft.com",
"name": "Samantha Booth"
},
"type": "required"
}
]
},
"headers": {
"Content-Type": "application/json"
}
},
{
"id": "3",
"url": "/me",
"method": "POST",
"body": {
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does late morning work for you?"
},
"start": {
"dateTime": "2017-04-15T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-15T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"samanthab#contoso.onmicrosoft.com",
"name": "Samantha Booth"
},
"type": "required"
}
]
},
"headers": {
"Content-Type": "application/json"
}
}
]
}
Execute code:
var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var result = await client.PostAsync(url, content);

Alexa Service Simulator Parse Error

I am trying to add custom skill to Alexa Echo Dot using VS2015 and Alexa.Net nuget packages.
I am able to upload the lambda function to Amazon Webservice. And I am able to see the skills.
However when I try to test the lambda function using Service Simulator, I am getting the error below
"The remote endpoint could not be called, or the response it returned was invalid."
"Parse error on line 1:
The remote endpoint ^ Expecting 'STRING', NUMBER', NULL ... "
I am not sure what really missing here. Here is the details
Lambda Request
{
"session": {
"sessionId": "SessionId.23409e06-265b-4704-a288-8d5329a68a68",
"application": {
"applicationId": "amzn1.ask.skill.55a9cca9-02dc-4780-a55c-c1d0dee6b8c6"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AHPIWHCHA22Z3WAJGS2ABA3MQ3PTKB4HOMJIBBDILIBPWTSAAOELN45D4PIV3U75IOBDHNGJQ36OSUYK43VQKYSQFIM2OHHOORSDWM2HMLWKINLCLKU7R3SNONWM7YPWSMR5XGN6XKVZGBG4NFHDQXACZLVK57MXUOIYYV6RLLVACBMMSFPVDINMO3QKQUZVZMVR73KTCEYTCRY"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.082b6e56-29d4-4eed-a353-e24890cfbefa",
"locale": "en-US",
"timestamp": "2017-07-11T12:19:27Z",
"intent": {
"name": "CountryInfoIntent",
"slots": {
"Country": {
"name": "Country",
"value": "France"
}
}
}
},
"version": "1.0"
}
Function Handler
public SkillResponse FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
return MakeSkillResponse(
$"Hello Infotec! This is the first response from your Alexa skill using c sharp.",
true);
}
else
{
return MakeSkillResponse(
$"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Canada.",
true);
}
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession, string repromptText = "Just say, tell me about Canada to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech { Text = outputSpeech }
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() { OutputSpeech = new PlainTextOutputSpeech() { Text = repromptText } };
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
It was a bug in the Alexa.Net nuget package. And that has been fixed in the latest package.
https://github.com/timheuer/alexa-skills-dotnet/commit/5c6dc0d2c0e3e16ca055d8938b1d0f24ad9670ed

How to commit a change to a file using the GitHub DB API

I am trying to update a file using the GitHub DB API using c#. The process for doing this is defined here http://developer.github.com/v3/git/ and is as follows
get the current commit object
retrieve the tree it points to
retrieve the content of the blob object that tree has for that particular file path
change the content somehow and post a new blob object with that new content, getting a blob SHA back
post a new tree object with that file path pointer replaced with your new blob SHA * getting a tree SHA back
create a new commit object with the current commit SHA as the parent and the new tree SHA, getting a commit SHA back
update the reference of your branch to point to the new commit SHA
However it fails when I get to the point of
update the reference of your branch to point to the new commit SHA
ie the line
var updateReferenceResponse = Patch<UpdateReferenceResponse>("git/refs/heads/master", updateReferenceRequest);
It fails with the response
<html><body><h1>502 Bad Gateway</h1>
The server returned an invalid or incomplete response.
</body></html>
Here is the specific API i am trying to call http://developer.github.com/v3/git/refs/#update-a-reference
Here is the main workings of the code
[Test]
public void UpdateFileUsingGithubDataApi()
{
var branch = GetUrlResponse<BranchResponse>("branches/master");
var currentCommitSha = branch.commit.sha;
var tree = GetUrlResponse<CommitResponse>("git/commits/" + currentCommitSha).tree;
var createBlob = new CreateBlobRequest
{
content = "sdkfn",
encoding = "utf-8"
};
var blobResponse = Post<CreateBlobResponse>("git/blobs", createBlob);
var blobSha = blobResponse.sha;
var createTreeRequest = new CreateTreeRequest
{
base_tree = tree.sha,
tree = new List<CreateTreeRequest.Tree>
{
new CreateTreeRequest.Tree
{
path = "README.md",
mode = "100644",
type = "blob",
sha = blobSha
}
}
};
var treeResponse = Post<CreateTreeResponse>("git/trees", createTreeRequest);
var createCommitRequest = new CreateCommitRequest
{
parent = new List<string>
{
currentCommitSha
},
message = "foo",
tree = treeResponse.sha
};
var commitResponse = Post<CreateCommitResponse>("git/commits", createCommitRequest);
var updateReferenceRequest = new UpdateReferenceRequest
{
sha = commitResponse.sha
};
var updateReferenceResponse = Patch<UpdateReferenceResponse>("git/refs/heads/master", updateReferenceRequest);
}
TResponse Post<TResponse>(string suffix, object value)
{
return Send<TResponse>(suffix, value, "Post");
}
TResponse Patch<TResponse>(string suffix, object value)
{
return Send<TResponse>(suffix, value, "Patch");
}
TResponse Send<TResponse>(string suffix, object value, string method)
{
var serializeObject = JsonConvert.SerializeObject(value, Formatting.Indented);
var sourceUrl = string.Format("https://api.github.com/repos/{0}/{1}/{2}", UserName, repo, suffix);
Debug.WriteLine("\r\n{0}ing to {1} with data\r\n{2}", method, sourceUrl, serializeObject);
var webRequest = WebRequest.Create(sourceUrl);
webRequest.Method = method;
AddAuth(webRequest);
var requestStream = webRequest.GetRequestStream();
using (var streamWriter = new StreamWriter(requestStream))
{
streamWriter.Write(serializeObject);
}
try
{
using (var webResponse = webRequest.GetResponse())
{
var text = webResponse.GetResponseStream().ReadToEnd();
Debug.WriteLine("response:\r\n" + text.GetPrettyPrintedJson());
return JsonConvert.DeserializeObject<TResponse>(text);
}
}
catch (WebException exception)
{
var readToEnd = exception.Response.GetResponseStream().ReadToEnd();
Debug.WriteLine("failed with response:\r\n" + readToEnd);
throw new Exception(readToEnd);
}
}
TResponse GetUrlResponse<TResponse>(string suffix)
{
var sourceUrl = string.Format("https://api.github.com/repos/{0}/{1}/{2}", UserName, repo, suffix);
var webRequest = WebRequest.Create(sourceUrl);
Debug.WriteLine("\r\nrequesting " + sourceUrl);
AddAuth(webRequest);
using (var webResponse = webRequest.GetResponse())
{
var text = webResponse.GetResponseStream().ReadToEnd();
Debug.WriteLine("response:\r\n"+ text.GetPrettyPrintedJson());
return JsonConvert.DeserializeObject<TResponse>(text);
}
}
void AddAuth(WebRequest webRequest)
{
if (UserName != null && Password != null)
{
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}", UserName, Password)));
webRequest.Headers.Add("Authorization", string.Format("Basic {0}", token));
}
}
Here is a transcript of the http conversation
requesting https://api.github.com/repos/simoncropp/test/branches/master
response:
{
"name": "master",
"commit": {
"sha": "a4447748c9cd36601127e3a6143348a1695cc2e8",
"commit": {
"message": "Initial commit",
"tree": {
"sha": "5b3438cf3aca03901bdb2ae1722bc7e05738a7fe",
},
"comment_count": 0
},
},
}
requesting https://api.github.com/repos/simoncropp/test/git/commits/a4447748c9cd36601127e3a6143348a1695cc2e8
response:
{
"sha": "a4447748c9cd36601127e3a6143348a1695cc2e8",
"tree": {
"sha": "5b3438cf3aca03901bdb2ae1722bc7e05738a7fe",
},
"message": "Initial commit",
"parents": []
}
Posting to https://api.github.com/repos/simoncropp/test/git/blobs with data
{
"content": "sdkfn",
"encoding": "utf-8"
}
response:
{
"sha": "2b664114096f7ff36664e381c5fbd0030f47009c",
}
Posting to https://api.github.com/repos/simoncropp/test/git/trees with data
{
"base_tree": "5b3438cf3aca03901bdb2ae1722bc7e05738a7fe",
"tree": [
{
"path": "README.md",
"mode": "100644",
"type": "blob",
"sha": "2b664114096f7ff36664e381c5fbd0030f47009c"
}
]
}
response:
{
"sha": "fd1379d51016989a615acf79409256849dc8ea7f",
"tree": [
{
"mode": "100644",
"type": "blob",
"sha": "bdc3535f745bc86966fb24c67d252c3ea68e8e03",
"path": ".gitignore",
"size": 1522,
},
{
"mode": "100644",
"type": "blob",
"sha": "e0369aaa94e2bc8dce560c0ae0669d74204602d5",
"path": "LICENSE",
"size": 1078,
},
{
"mode": "100644",
"type": "blob",
"sha": "2b664114096f7ff36664e381c5fbd0030f47009c",
"path": "README.md",
"size": 5,
}
]
}
Posting to https://api.github.com/repos/simoncropp/test/git/commits with data
{
"message": "foo",
"tree": "fd1379d51016989a615acf79409256849dc8ea7f",
"parent": [
"a4447748c9cd36601127e3a6143348a1695cc2e8"
]
}
response:
{
"sha": "f66832493d22c58a6dd9d41b65504c1e9c901d7a",
"tree": {
"sha": "fd1379d51016989a615acf79409256849dc8ea7f",
},
"message": "foo",
"parents": []
}
Patching to https://api.github.com/repos/simoncropp/test/git/refs/heads/master with data
{
"sha": "f66832493d22c58a6dd9d41b65504c1e9c901d7a"
}
failed with response:
<html><body><h1>502 Bad Gateway</h1>
The server returned an invalid or incomplete response.
</body></html>
Posting to https://api.github.com/repos/simoncropp/test/git/commits with data
{
"message": "foo",
"tree": "fd1379d51016989a615acf79409256849dc8ea7f",
"parent": [
"a4447748c9cd36601127e3a6143348a1695cc2e8"
]
}
The docs are expecting a parents parameter here, not parent.
response:
{
"sha": "f66832493d22c58a6dd9d41b65504c1e9c901d7a",
"tree": {
"sha": "fd1379d51016989a615acf79409256849dc8ea7f",
},
"message": "foo",
"parents": []
}
Without it, you get an empty array of parent commits, and Bad Things Will Happen.

Categories

Resources