UWP client PUT and POST Requests Fails with PHP API - c#

I have a problem when I´m trying sending post and put requests to my webapi (the server side is coded in php and works with mysql).
If I try to send a get request there is no problem at all, the API responds properly, the problem comes when I try to send a body in request (that´s why I think post and put fails).
I am sure that my api works well, as long as I have done tests with postman and another clients and they all follow a correct way with these requests.
The API responds 400 Bad Request and I don´t know what to do. I´ve done the same api coded in C# and my code in client-side works, there´s any incompatibility between Universal Windows Platform and PHP API´s?
My PUT method:
public async Task<int> updateFestivalDAL(Festival festival)
{
int resultado = 0;
Uri miConexion = (new clsMyConnection().getConnection());
HttpClient miCliente = new HttpClient();
String body = "";
HttpStringContent contenido;
HttpResponseMessage miRespuesta = new HttpResponseMessage();
try
{
body = JsonConvert.SerializeObject(festival);
contenido = new HttpStringContent(body, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");
miRespuesta = await miCliente.PutAsync(new Uri(miConexion + "/" + festival.ID), contenido);
if (miRespuesta.IsSuccessStatusCode)
{
resultado = 1;
}
}
catch (SqlException e)
{
throw e;
}
return resultado;
}
That´s my body in request:
"{\"ID\":1,\"edicion\":\"Prueba año anterior\",\"nombre\":\"fgh\",\"fecha_inicio\":\"2017-10-01T00:00:00\",\"fecha_fin\":\"2017-10-03T00:00:00\",\"coordenadas\":\"asdf\",\"twitter\":\"\",\"facebook\":\"\",\"instagram\":\"\",\"web\":\"\",\"curiosidades\":\"\"}"
And that´s my API response (miRespuesta variable value):
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 2, Content:
Windows.Web.Http.HttpStreamContent, Headers:
{
Connection: close
Server: Apache/2.4.34 (Win32) OpenSSL/1.0.2o PHP/5.6.38
Date: Wed, 31 Oct 2018 21:47:36 GMT
X-Powered-By: PHP/5.6.38
}{
Content-Length: 0
Content-Type: text/html; charset=UTF-8
}}
Please help me if you know something.
UPDATE: When I see content of miCliente variable (the one with httpclient), I can see there´s a list element called DefaultRequestHeaders. Maybe there´s the problem? I have to edit these to make them compatible with PHP?
UPDATE 2:
I´ve changed two dates elements (fecha_inicio, fecha_fin) in database and my Festival class, so they are now varchar (string at class), trying if the problem was parsing datetimes and try saving as date in database, but still not work.
Postman successfully request:
PUT /festival/1 HTTP/1.1
Host: notrelevantbutwellformed.com
Content-Type: application/json
cache-control: no-cache
Postman-Token: 100313d6-7087-4712-8b93-17873e1db14b
{
"ID": "1",
"edicion": "fgh",
"nombre": "fgh",
"fecha_inicio": "2018-11-01",
"fecha_fin": "2018-11-01",
"coordenadas": "asdf",
"twitter": "asfd",
"facebook": "ffsd",
"instagram": "asrss",
"web": "noo va a petar",
"curiosidades": "sdfsdfdsf",
"url_logo": "",
"url_cartel": ""
}------WebKitFormBoundary7MA4YWxkTrZu0gW--

Related

.NET Core Web API only gets JSON from the Mock Lambda Tool. Using Postman, Swagger & AWS Lambda fail

I recently wrote a .NET Core Web API to receive JSON from a Lambda SNS message event. The Lambda sends the SNS event message JSON (via a POST request) to the API.
When I use the 'Mock Lambda Tool' to send the SNS message to the API, all is well. It works great. The data arrives, my API's controller sees it and it sends it over to the class that parses the data sends it into a database.
So, I then published the API to IIS and tested it from the Mock Lambda Tool. That worked too.
Feeling good about the work I uploaded the Lambda to AWS (for real world scenarios), I did a quick test of the same SNS message (JSON) using the AWS Lambda console. It times out.
So, I decided to go back and try testing the API on IIS using Postman. It shows:
**POST** https://my.company.com/api/Transaction/
**201**
2.69 s
POST /api/Transaction/ HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Cache-Control: no-cache
Postman-Token: 4173d96a-1583-4c64-82b1-f67acaf8f0c7
Host: my.company.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 4274
*(I'm omitting the HUGE json message area. It's standard format.)*
**HEADER INFO**
HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Location: https://my.company.com/api/Transaction/
Server: Microsoft-IIS/10.0
Date: Wed, 10 Aug 2022 01:04:41 GMT
**RESPONSE BODY**
{"Id":0,"email":null,"token":null,"storeNumber":null,"transactionDateTime":"0001-01-01T00:00:00","transactionId":null,"orderData":null}
There is NO error, but note that the Response Body is all nulls.
I decided to run the API from Visual Studio so that I could step through the code as the SNS message arrives from the Lambda.
Using the Mock Lambda Tool, no errors. Data goes all the way through.
Using Postman, a breakpoint on the controller shows no Transaction data arriving (NULL).
Using Swagger, a breakpoint on the controller shows no Transaction data arriving (NULL).
Are there any ideas as to what I am missing or doing incorrectly?
This is my controller in the API:
using Microsoft.AspNetCore.Mvc;
using MyWebAPI.TransactionData;
using MyWebAPI.Models;
namespace MyWebAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class TransactionController : ControllerBase
{
private readonly ITransactionData _transactionData;
public TransactionController(ITransactionData transactionData)
{
_transactionData = transactionData;
}
[HttpGet]
public string Get()
{
return "You have reached the .NET Core Web API (web service).";
}
[HttpPost]
public IActionResult DataTranslation(Transaction transactionData)
{
_transactionData.DataTranslation(transactionData); // entry point
return Created(
HttpContext.Request.Scheme
+ "://" + HttpContext.Request.Host
+ "" + HttpContext.Request.Path
+ "/" + transactionData.transactionId, transactionData
);
}
}
}
Here is my POST request in the Lambda:
public void PostRequest(string msg)
{
var url = "https://my.company.com/api/Transaction/"; // IIS
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.Accept = "application/json";
httpRequest.ContentType = "application/json";
var data = msg;
try
{
// Write request data to stream
using (var streamWriter = new StreamWriter(httpRequest.GetRequestStream()))
{
streamWriter.Write(data);
}
// Get a response from IIS (REST API)
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
// Read the body of the response from the server
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
// Log the status code
Log.Logger.Information(#"httpResponse: " + httpResponse.StatusCode);
}
catch (WebException wex)
{
Log.Logger.Information($"[ERROR] WebException, {wex}");
Log.Logger.Information($"[ERROR] WebException Message, {wex.Message}");
Log.Logger.Information($"[ERROR] WebException Response, {wex.Response}");
Log.Logger.Information($"[ERROR] WebException Response, {wex.Response.Headers}");
Log.Logger.Information($"[ERROR] WebException Response, {wex.Response.ResponseUri}");
string pageContent = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd().ToString();
Log.Logger.Information($"[ERROR] pageContent, {pageContent}");
}
catch (Exception ex)
{
Log.Logger.Information($"[ERROR] Exception, {ex}");
}
return;
}
I'm curious if it's my Post Request that is the problem?
Why is the 'Mock Lambda Tool' the only way I can get the data over to the API?
Thanks
Is it because you are sending the JSON in the request body vs querystring?
Try using
[HttpPost]
public IActionResult DataTranslation([FromBody] Transaction transactionData)
{
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api#using-frombody
message using
UPDATE. I learned that the Lambda at AWS required a VPC to my internal VM that hosts the API on IIS. That solves why the Lambda at AWS timed out repeatedly.
As for Postman and Swagger problem, the issue is that the Mock Lambda Tool sends the entire SNS message event in its natural full format, then the Lambda extracts the Message portion only to send over to the API.
I was sending this entire SNS message event across Swagger and Postman both of which DO NOT do the work that the Lambda does which is strip just the Message portion out of the SNS event.
Once I sent only the Message portion across with Swagger and Postman, both worked.
I must give credit to my work buddy Dorian for helping me with this. Thanks! :)

Error 500 Sending JSON POST Request to API

I'm developing an app in Xamarin.Forms (Shared Project Library) that sends a list of custom types (just a document number and a file type enumeration) to a locally hosted API.
If I capture the JSON string and send it from Postman, everything works fine, but as soon as I run the httpClient.PostAsync from the app, I receive the following error:
{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1,
Content: System.Net.Http.StreamContent, Headers: { Cache-Control:
no-cache Pragma: no-cache Server: Microsoft-IIS/7.5 X-AspNet-Version:
4.0.30319 X-Powered-By: ASP.NET Date: Thu, 25 May 2017 16:00:44 GMT Content-Type: application/json; charset=utf-8 Expires: -1
Content-Length: 36 }}
I'm at a loss a to what I'm doing wrong. Can anyone help, please?
Type:
class EmailFiles
{
public string docNumber { get; set; }
public EmailFileTypes.EmailFileType type { get; set; }
}
Request:
List<EmailFiles> files = new List<EmailFiles>();
if (chkShipping.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.CustomerFile;
file.docNumber = Helpers.GlobalVariables.gSOLookup.PackList;
files.Add(file);
}
if (chkClosed.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.ClosedFile;
file.docNumber = Helpers.GlobalVariables.gSOLookup.Invoice;
files.Add(file);
}
if (chkInvoice.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.Invoice;
file.docNumber = Helpers.GlobalVariables.gSOLookup.Invoice;
files.Add(file);
}
string url = SetUrls.urlMtApi + "/api/EmailFile/?emailAddresses=" + strEmails;
string strJson = JsonConvert.SerializeObject(files);
//Results in: "[{\"docNumber\":\"234273\",\"type\":1},{\"docNumber\":\"633007\",\"type\":2}]" - which works in Postman!!
StringContent content = new StringContent(strJson, Encoding.UTF8, "application/json");
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(url, content);
Web Service:
[System.Web.Http.HttpPost]
public string EmailFile([FromBody]string jsonfiles, [FromUri] string emailAddresses)
{
List<EmailFiles> files = JsonConvert.DeserializeObject<List<EmailFiles>>(jsonfiles);
...
}
No need to manually deserialize the json body, just let the model binder do it for you by using correct parameters:
[System.Web.Http.HttpPost]
public MyModelReturnType EmailFile([FromBody] List<EmailFiles> files, [FromUri] string emailAddresses)
{
// the framework has already deserialized the json request for you
}
If you use string instead of the true model for your parameter the server will not be able to bind your request body to it, because it will expect a JSON string (surrounded by double quotes "), and this could cause a model binding exception that will lead to a 500 error in your client.
The same is for the return type, just use whatever class you want your client to receive as return type and do not use string if you want to send it Json.

WepAPI Method is throwing MethodNotAllowed but I don't know why

I think the answer is something simple, but I have a method throwing a 405 not allowed error and I'm not sure why. Before I get into details I'll point out something that seems like a clue - the method that works is actually called Get - and I'm not sure if there is some HTTP method mapping done behind the scenes that causes that to work.
I have a controller with multiple methods in it. So far I'm testing 2 of them and the first one works just fine, yet the second is throwing the error.
My controller is OOB setup, my logic and model are in separate projects. The following method is called and returns correctly:
[Route("api/GetFastPlan/{key}/{clientID}/{fastPlanID}")]
public RequestFastPlanResult Get(string key, string clientID, int fastPlanID)
{
return new FastPlanFileShare().RequestFastPlan(key, clientID, fastPlanID);
}
This method however is throwing a 405.
[Route("api/UpdateDownloads/{key}/{clientID}/{fastPlanID}")]
public UpdateDownloadsResult UpdateDownloads(string key
, string clientID, int fastPlanID)
{
return new FastPlanFileShare().UpdateNumberOfDownloadsColumnFastPlan(key
, clientID, fastPlanID);
}
I am calling them both with the same code setup, which is here in my test project:
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://localhost:8129/api/UpdateDownloads/value1/value2/1082");
HttpResponseMessage response = httpClient.GetAsync("http://localhost:8129/api/UpdateDownloads/value1/value2/1082").Result;
Assert.IsTrue(response.IsSuccessStatusCode);
if (response.IsSuccessStatusCode)
{
var rp = response.Content.ReadAsAsync<ServiceReference2.RequestFastPlanResult>();
Assert.IsTrue(rp.Result.ServiceResult.WasSuccessful);
}
}
full error:
{StatusCode: 405, ReasonPhrase: 'Method Not Allowed', Version: 1.1,
Content: System.Net.Http.StreamContent, Headers: { Pragma: no-cache
X-SourceFiles:
=?UTF-8?B?RDpcUHJvamVjdHNcTkVUMjAxK1xFeWVNRCBFTVIgSW50ZXJuYWwgV2Vic2VydmljZXNcRU1SU2VydmljZXMuV2ViQVBJXGFwaVxVcGRhdGVEb3dubG9hZHNcZXllbWRlbXIjMVxFWUU5ODQ1NFwxMDgy?=
Cache-Control: no-cache Date: Wed, 06 Jan 2016 13:50:43 GMT
Server: Microsoft-IIS/10.0 X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET Content-Length: 72 Allow: POST
Content-Type: application/json; charset=utf-8 Expires: -1 }}

Log In With Paypal Unauthorized 'error:access_denied'

I am attempting to set up Log In With Paypal, but I am receiving a Unauthorized Message ("{\"error_description\":\"Unable to generate token\",\"error\":\"access_denied\"}") while obtaining the access token ( I received the authorization code without a hiccup). The only thing I think I might have wrong is the availability of this service to non US residents. It says that REST APIs is not available to non US residents, but I noticed that its segregated from the 'Log In With Paypal'. Does anyone know?
Here is the code I am using too retrieve the access token in case anyone can notice an error:
string TokenEndpoint = "https://api.paypal.com/v1/identity/openidconnect/tokenservice";
System.Collections.Specialized.NameValueCollection reqparm = new System.Collections.Specialized.NameValueCollection();
reqparm.Add("client_id", this._clientId);
reqparm.Add("client_secret", this._clientSecret);
reqparm.Add("grant_type", "authorization_code");
reqparm.Add("code", authorizationCode);
reqparm.Add("redirect_uri", HttpUtility.UrlEncode(returnUrl.AbsoluteUri));
try
{
using (WebClient client = new WebClient())
{
var data = client.UploadValues(TokenEndpoint, "POST", reqparm); // Access Denied exception occurs here.
...
Here is the response I receive:
HEADER
{
Pragma: no-cache
Vary: Accept-Encoding
Connection: close
Content-Length: 72
Cache-Control: no-store
Content-Type: application/json
Date: Mon, 10 Jun 2013 23:35:02 GMT
Server: Apache-Coyote/1.1
}
Content
text
{
\"error_description\":\"Unable to generate token\",
\"error\":\"access_denied\"
}"

Get Response with HttpClient

I'm trying to use HttpClient to read the response content from a 3rd party API (Rackspace Cloud Files). Here's what I have so far. I can't seem to get the content.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Auth_User", username);
client.DefaultRequestHeaders.Add("X-Auth-Key", api);
client.GetAsync("identity.api.rackspacecloud.com".ToAbsoluteUrl()).ContinueWith(
(requestTask) =>
{
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
response.Content.ReadAsAsync<string>().ContinueWith(
(readTask) =>
{
var result = readTask.Result;
});
});
This gives me "No 'MediaTypeFormatter' is available to read an object of type 'String' with the media type 'text/html'." error.
I need to retrieve the response details as noted in the Rackspace docs (example):
HTTP/1.1 204 No Content
Date: Mon, 12 Nov 2007 15:32:21 GMT
X-Storage-Url: https://storage.clouddrive.com/v1/CF_xer7_34
X-CDN-Management-Url: https://cdn.clouddrive.com/v1/CF_xer7_34
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
How do I get the response?
When I use ReadAsStringAsync, it gives my the HTML source of my page.
Thank you.

Categories