C# - PostAsync response returning empty array - c#

I am writing a mobile application in Xamarin.Forms, and have a very simple PHP file for my back end. The mobile application sends a post request to the PHP file, and the PHP file is meant to var_dump the post contents.
<?php
echo "Your post response is...";
var_dump($_POST);
?>
My Xamarin application uses the HttpClient class to create a simple post request using the PostAsync() method.
public class RestService
{
HttpClient client;
private const string URL = "https://braz.io/mobile.php";
public RestService()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
public async Task<string> getUserInformation()
{
User u = new User("Barns", "password1234", "email#email.com");
string json = JsonConvert.SerializeObject(u);
var uri = new Uri(string.Format(URL, string.Empty));
try
{
client.DefaultRequestHeaders.Add("Accept", "application/json");
StringContent s = new StringContent(json);
var response = await client.PostAsync(uri, s);
string body = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{Console.WriteLine(ex);}
return null;
}
}
For some reason, my post request is only getting the response Your post resonse is... followed by an empty array. It is strange, because when I use PostMan on google chrome, it returns the correct information.
I have checked that my json variable has valid JSON in it as well, so I am unsure why the PostAsync function is returning/sending an empty array from/to my PHP file.
UPDATE as per comment request
The JSON I am sending is as follows:
"{\"username\":\"Barney\",\"password\":\"1234\",\"email\":\"email#email.com\"}"
My user class is:
public class User
{
public User(){ }
public string username { get; set; }
public string password { get; set; }
public string email { get; set; }
public User(string username, string password, string email)
{
this.username = username;
this.password = password;
this.email = email;
}
}

The issue has nothing to do with the Xamarin side of things. Your issue lies in the PHP code you provided and the fact that when you tried sending something with POSTman, you didn't send it as the body of the request.
In order to read the request body, you need to read the input stream:
$json = file_get_contents('php://input');
Then you can output that with
var_dump($json);
As for your RestService code, I would advise you to provide the content type for your string content:
var s = new StringContent(json, Encoding.UTF8, "application/json");

Related

Send binarydata to Azure webAPI POST endpoint

Currently my webAPI has the following POST endpoint:
public async Task<ActionResult<string>> AddUserImage([FromRoute] string userId, [FromHeader] bool doNotOverwrite, [FromBody] byte[] content, CancellationToken ct)
My goal is to send an image file to the endpoint. However, I cannot find a correct way to send an octect-stream or ByteArrayContent or some other type over the internet. All attempts end in an HTTP 415.
This is my best attempt to send the image over the internet:
public async Task<bool> AddOrReplaceImage(string id, string endpoint, byte[] imgBinary)
{
if (imgBinary is null) throw new ArgumentNullException(nameof(imgBinary));
var request = new HttpRequestMessage(HttpMethod.Post, endpoint);
request.Headers.Add("doNotOverwrite", "false");
request.Content = JsonContent.Create(imgBinary);
// I also tried: request.Content = new ByteArrayContent(imgBinary);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // Does not seem to change a thing
var apiResult = await new HttpClient().SendAsync(request); // Returns 415
return apiResult.IsSuccessStatusCode;
}
I doubt both the parameters of the endpoint and the way I send the HTTP request. How can I simply receive and send an image over the internet?
Frist Solution :- Which worked in my case.
You can try [FromForm] and IFormFile Like this :-
If controller is annotated with [ApiController] then[FromXxx] is required. For normal view controllers it can be left.
public class PhotoDetails
{
public string id {get;set;}
public string endpoint {get;set;}
public IFormFile photo {get;set;}
}
public async Task<ActionResult<string>> AddUserImage([FromForm] PhotoDetails photoDetails, CancellationToken ct)
I tried this in .net core and it worked but i needed array of files so i used [FromForm] and IFormFile[] and sending from angular.
Second Solution :-
I tried replicate question scenario with question code.
and then changed the implementation and it worked. Please find the below
code
PhotoDetails photopara = new PhotoDetails();
photopara.id = id;
photopara.endpoint = endpoint;
photopara.photo = imgdata;
string json = JsonConvert.SerializeObject(photopara);
var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
var response = await client.PostAsync("http://localhost:57460/WeatherForecast", stringContent);
if (!response.IsSuccessStatusCode)
{
return null;
}
return (await response.Content.ReadAsStreamAsync()).ToString();
}
public class PhotoDetails
{
public string id {get;set;}
public string endpoint {get;set;}
public byte[] photo {get;set;}
}
In this solution, I changed IformFile to byte[] in photodetail class because httpresponsemessage creating problem.
Get Image or byte array in Post Method
Please try this without json serialization
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(idContent, "id", "param1");
formData.Add(endpointContent, "endpoint", "file1");
formData.Add(bytesContent, "photo", "file2");
var response = await client.PostAsync("http://localhost:57460/WeatherForecast", formData);
if (!response.IsSuccessStatusCode)
{
return null;
}
return (await response.Content.ReadAsStreamAsync()).ToString();
}
public async Task<ActionResult<int>> AddUserImage([FromForm] PhotoDetails photo, CancellationToken ct)
{
// logic
}
Still Not working then You can try the below link also
Send Byte Array using httpclient

C# HTTPClient Not Sending Request

I have a WPF application where I need to retrieve configuration data from a remote API. The API has been tested and is working correctly returning what I believe to be the correct format. I have created a data type for the response etc etc but when I get to the line getting the response via the HttpClient it doesn't send any request to the API.
DataType :-
public class Mylist
{
public string ItemName { get; set; }
public string ItemText { get; set; }
public string ConfigName { get; set; }
public string ConfigValue { get; set; }
public string ConfigType { get; set; }
}
Code :-
string licKey = ConfigManager.GetSetting("Lic");
string Uri = ConfigManager.GetSetting("API");
string UserAPI = ConfigManager.GetSetting("Config");
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(Uri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync(UserAPI + "?Licence=" + licKey);
var data = await response.Content.ReadAsAsync<IEnumerable<Mylist>>();
int count = 0;
List<Mylist> nudges = new List<Mylist>((IEnumerable<Nudgelist>)data);
// Do something with the data
the code builds the correct URL (https://example.com/api/Uri?Licence=licencevalue) for the request and if input manually into the browser it gives a response as per the below :-
<Mylist>
<ConfigName>cName</ConfigName>
<ConfigType>cType</ConfigType>
<ConfigValue>cValue</ConfigValue>
<ItemName>iName</NudgeName>
<ItemText>iText</NudgeText>
</Mylist>
<Mylist>
...
</Mylist>
When I run the code above and step through it then we get to the line "var response = await client.GetAsync(UserAPI + "?Licence=" + licKey);" and it just skips the rest of the code and moves onto the next call, no error raised or failures anywhere to be found.
I have run logs on the API and we are not seeing the request coming in, if we use an identical model of code for calling another API controller to call Uri2 (https://example.com/api/Uri2?Licence=licencevalue) it works fine.
Try this
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IEnumerable<MyList>>(stringData);
}
else
{
var statusCode= response.StatusCode);
}

WebApi HttpPost not receiving the posted content from HttpClient

Web API:
I tried using [FormBody] and [FromForm] before the string stringcontent as well.
// POST api/<MAUserController>
[HttpPost("AuthenticateUser")]
public async Task<ActionResult<MAUser>> PostAsync(string stringcontent)
{
//stringcontent is null
}
Client Code:
List<KeyValuePair<string, string>> postParameters = new List<KeyValuePair<string, string>>();
postParameters.Add(new KeyValuePair<string, string>("Email", Email));
postParameters.Add(new KeyValuePair<string, string>("Password", Password));
var jsonString = JsonConvert.SerializeObject(postParameters);
var stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
//httpClient.DefaultRequestHeaders.Add("Email", Email);
//httpClient.DefaultRequestHeaders.Add("Password", Password);
using (var response = await httpClient.PostAsync(API_URL, stringContent))
{
if (response.IsSuccessStatusCode)
{
//Success code
}
else
{
//Handle unsuccessful here
}
}
You're posting structured data in JSON format from the client. So why is the API just trying to accept a plain string? That doesn't make a lot of sense.
You should make it accept a model object with the correct structure, instead. ASP.NET will take care of binding the JSON properties to the model properties. However, you should also simplify the postParameters in the client as well - you're over-complicating the structure.
e.g.
Client:
var postParameters = new { Email = "abc#example.com", Password = "xyz" };
Server:
public async Task<ActionResult<MAUser>> PostAsync([FromBody] UserCredentials credentials)
{
}
where UserCredentials is a DTO class like this:
public class UserCredentials
{
public string Email { get; set; }
public string Password { get; set; }
}
ok so when using content type you are basically telling the receiving API how to parse the request payload and so by telling it application/json the framework is trying to parse the payload from JSON to an object and assign it to your parameter ( not really since you need to add an attribute [FromBody] ) but it can not do it since you are expecting a string, so either change your content type or change your parameter type ( i would suggest your parameter type ) .

JSON in body of POST then extract the body of the response to get the access_token

I have this small Python application that I wrote last year that I need to remake in C#. I don't really know C#, but need to make a connection between Dynamics 365 and QuickBooks Desktop which uses C# (or C++, Java, VB... none of which I know).
As I said, the Python app works fine, and I get what I need from D365 via Postman, put having a hell of time getting it working for C#. There is a sample project here, but trying to interpret what is going on is making my head spin (it doesn't run either otherwise I'd just use it).
This is what I currently do:
class Program
{
static void Main(string[] args)
{
ConnectToCRM();
}
static void ConnectToCRM()
{
string crmOrg = "https://company.api.crm.dynamics.com";
string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
string clientSecret = "super_secret_stuff";
string username = "me#company.biz";
string userPassword = "password";
string authorizationEndPoint =
"https://login.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/authorize";
string crmWebApi = "https://company.api.crm.dynamics.com/api/data/v8.2";
var values = new Dictionary<string, string>
{
{"client_id", clientId},
{"client_secret", clientSecret},
{"resource", crmOrg},
{"oauthUrl", authorizationEndPoint},
{"username", username},
{"password", userPassword},
{"grant_type", "password"}
};
HttpRequestToCrm(values);
}
public class ServerResponse
{
public string token_type { get; set; }
public string scope { get; set; }
public string expires_in { get; set; }
public string ext_expires_in { get; set; }
public string expires_on { get; set; }
public string not_before { get; set; }
public string resource { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
}
static async void HttpRequestToCrm(Dictionary<string, string> values)
{
string tokenEndPoint = "https://login.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/token";
var client = new HttpClient();
var content = new FormUrlEncodedContent(values);
try
{
HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(response);
Console.WriteLine(responseContent);
ServerResponse rb = JsonConvert.DeserializeObject<ServerResponse>(responseContent);
Console.WriteLine(rb.token_type);
}
catch (WebException e)
{
Console.WriteLine("catch");
Console.WriteLine(e);
throw;
}
}
}
As I understand it I need to be using FormUrlEncodedContent for x-www-form-urlencoded, as x-www-form-urlencoded is what I have to do in Postman for it to work. Python just seems to be doing it.
Console.WriteLine(content); just says System.Net.Http.FormUrlEncodedContent. The Console.WriteLine(response); actually has something in it now, where it didn't before: System.Threading.Tasks.Task1[System.Net.Http.HttpResponseMessage]. I need to get the response body, so that I can get theaccess_token` and then finally actually query the D365 web API.
How do I get the response body and the access_token? How do I even see that that is what it is responding with? Is my approach entirely wrong?
EDIT:
Whether or not I do:
HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);
Or:
var response = await client.PostAsync(tokenEndPoint, content);
Visual Studio Community 2017 quits running at that line and doesn't trigger any kind of error. I'll sent a break point there, then F10 or F11, and it exits the program.
Found this regarding it:
Code Execution stops with no error
Turned on all the options, but still can't see why it is just ending.
This is a screenshot of what I'm trying to do working in Postman. I'm obviously just doing something wrong in C#.
Try this to get the Content of the Response:
HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);
if(!response.IsSuccessStatusCode) return; // optional
string responseContent = await response.Content.ReadAsStringAsync();
First of all you need to await the PostAsync() call. Since this only leaves you with a HttpResponseMessage then and not the actual content of the response, you'd have to get it in a second step by reading the response's Content Property as a string.
If your Response returned an OK (HTTP 200 Status Code) this code should leave you with responseContent holding the desired response as a string.
I assume that your access_token is a JSON Property in this received string, so you would have to then deserialize it or use a extracting mechanism to get the actual access_token from said string. There are already plenty of posts on StackOverflow regarding this, so i won't elaborate on it any further.
Couple things right off the bat, you aren't awaiting your PostAsync call so you don't really have the response stored.
Second, C# doesn't automatically serialize objects like that when you tell it to write to the console so it is just telling ou what kind of object it is, aka a task that is wrapping an HttpResponseMessage.
The following should get you the response body (assuming it is just the token this will work fine for you). You'll need to modify it some to work perfectly for you, but this should get you started.
try
{
var response = await client.PostAsync(tokenEndPoint, content);
//read the response body as a string here
string token = await response.Content.ReadAsStringAsync();
Console.WriteLine(response);
}
catch (WebException e)
{
Console.WriteLine("catch");
Console.WriteLine(e);
throw;
}

Consume WCF Restful service with datacontract

I have created the following restfull web service:
Interface
[ServiceContract]
public interface ISIGService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetTicket/")]
Ticket GetTicket(string user, string pwd);
}
Implementation
public class SIGService : ISIGService
{
public Ticket GetTicket(string user, string pwd)
{
return new Ticket()
{
Usuario = "xx",
UsuarioNombre = "xxx",
UsuarioId = "xxx"
};
}
Contract
[DataContract]
public class Ticket
{
[DataMember]
public int UsuarioId { get; set; }
[DataMember]
public string UsuarioNombre { get; set; }
[DataMember]
public string Usuario { get; set; }
}
I need to consume this service, from a web application, and get the typed object Ticket, I have included a service reference for this.
Server side code:
string urlService =
String.Format("http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'",
usuario, password);
var request = (HttpWebRequest)WebRequest.Create(urlService);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
I put a text variable just to get something, sort of lost here.
I don't seem to get this object, could you give some pointers on this?
Most likely, you just need to change your URL from
http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'
to using the proper REST syntax (since you're using a REST service):
http://localhost:22343/SIGService.svc/GetTicket/{user}/{pwd}
Sample:
http://localhost:22343/SIGService.svc/GetTicket/daniel/topsecret
No ? or user= or single quotes necessary ....
With this, the value from {0} will be passed into the user parameter, and the value from {1} to the pwd parameter.
For consuming the service, I would recommend you check out the excellent RestSharp library which makes using your REST service a breeze.
Your code would look something like this:
// set up the REST Client
string baseServiceUrl = "http://localhost:22343/SIGService.svc";
RestClient client = new RestClient(baseServiceUrl);
// define the request
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.RequestFormat = DataFormat.Xml;
request.Resource = "GetTicket/{user}/{pwd}";
request.AddParameter("user", "daniel", ParameterType.UrlSegment);
request.AddParameter("pwd", "top$ecret", ParameterType.UrlSegment);
// make the call and have it deserialize the XML result into a Ticket object
var result = client.Execute<Ticket>(request);
if (result.StatusCode == HttpStatusCode.OK)
{
Ticket ticket = result.Data;
}

Categories

Resources