call REST API in xamarin - c#

I design a login form in xamarin Form PCL and I want to call a my webservice that will return JSON. For this, I created two functions for the same but both are n is not returning values.
Can you please tell me what I am doing wrong?
async void OnLoginButtonClick(object sender, EventArgs e)
{
if (usernameEntry.Text != "" && passwordEntry.Text != "")
{
var response = GetLoginDetails(usernameEntry.Text,passwordEntry.Text);
var getData = await getDataFromService(usernameEntry.Text, passwordEntry.Text);
}
}
public static async Task<HttpResponseMessage> GetLoginDetails(string username, string password)
{
try
{
var httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://mywebserverIP/api/Users?Username=" + username + "&Password=" + password);
var response = await httpClient.SendAsync(request);
return response;
}
catch (Exception ex)
{
throw;
}
}
public static async Task<dynamic> getDataFromService(string username, string password)
{
using (var client = new HttpClient())
{
var responseText = await client.GetStringAsync("http://mywebserverIP/api/Users?Username=" + username + "&Password=" + password);
dynamic data = JsonConvert.DeserializeObject(responseText);
return data;
}
}
Thanks for your comment in Advance.

As you not awaiting the first method , request thread will not wait till it returns the value so , 1st change you have to make is to
var response = await GetLoginDetails()
For the second method
var getData = await getDataFromService()
I do not see any issue. I am not sure how you know that this method is not returning any values. Better to log the response of the both the method call and check.

Use await.
First in the
var response = await GetLoginDetails(...
then maybe in the deserializeobject method too (this one i'm not sure)
dynamic data = await Task.Run(() => JsonConvert.DeserializeObject(responseText));

Related

How to get body content in a http client call?

I am unable to get body content in this http client call, because I can't figure out how to get the actual content of the request in this async method.
Here's the async method:
public async Task<HttpResponseMessage> AuthenticateUser(string username, string password)
{
var client = new HttpClient();
var requestUri = new Uri($"{_authorityBaseUrl}/{_tenantID}/oauth2/token");
var authenticationBody = CreatePasswordGrantConsent(username,password);
return await client.PostAsync(requestUri, authenticationBody);
}
Here's the method that I wanna get the body content from
protected void loginBtn_Click(object sender, EventArgs e)
{
AADConnector connector = new AADConnector();
var result = connector.AuthenticateUser("username", "password").Result.Content;
}
I've tried in AuthenticateUser method to change to :
public async Task<string>(string username , string password)
{
...
...
var response = await client.PostAsync(requestUri, authenticationBody);
var contents = await response.Content.ReadAsStringAsync();
return contents;
}
And change in loginBtn_Click to :
AADConnector connector = new AADConnector();
Task<string> result = connector.AuthenticateUser("username","password");
var finalResult = result.Result;
But it just deadlocks and it keeps running forever.
Can you guys explain me why this happens?
Here is how I did it:
public async Task<string> AuthenticateUser(string username, string password)
{
var client = new HttpClient();
var requestUri = new Uri($"{_authorityBaseUrl}/{_tenantID}/oauth2/token");
var authenticationBody = CreatePasswordGrantConsent(username, password);
var response = await client.PostAsync(requestUri, authenticationBody);
var result = await response.Content.ReadAsStringAsync();
return result;
}
AADConnector connector = new AADConnector();
var result = Task.Run(async () => await connector.AuthenticateUser("username", "password"));
try {
result.Wait();
} catch {
}
dynamic data = JObject.Parse(result.Result);
string token = (string)data.access_token;

How to have an API call working? Currently my call to client is not working

I have an API in .net 5 that runs locally. One of the endpoints is https://localhost:44362/User
Now, I created a console app that will consume the API and defined a method to call the get User.
public async Task<bool> CallAPI()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44362/");
using (HttpResponseMessage response = await client.GetAsync("User"))
{
var resContent = response.Content.ReadAsStringAsync().Result;
return true;
}
}
}
Here is the code in the API
[HttpGet]
public IEnumerable<User> Get()
{
using (var context = new ohabartContext())
{
return context.Users.ToList();
}
}
But when the code using (HttpResponseMessage response = await client.GetAsync("User")) is executed nothing happens. I don't receive any error or whatsoever. I search the net and all other codes look the same in consuming or calling an API.
What seems to be the problem?
ReadAsStringAsync() Serialize the HTTP content to a string as an asynchronous operation. This operation will not block. The returned Task object will complete after all of the content has been written as a string.
HttpResponseMessage response= await client.GetAsync(u);
var resContent = await response.Content.ReadAsStringAsync().Result;
Once the operation completes, the Result property on the returned task object contains the string with the HTTP content.
public async Task<bool> CallAPI()
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44362/");
HttpResponseMessage response = await client.GetAsync(u);
var resContent = awit response.Content.ReadAsStringAsync().Result;
return true;
}
}
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} " , e.Message);
return false;
}
}
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-6.0
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.getasync?view=net-6.0

HttpClient post returns bad request in c#, works in postman

I'm trying to access a rest endpoint, https://api.planet.com/auth/v1/experimental/public/users/authenticate. It is expecting json in the request body.
I can get the request to work in Postman but not using c#. Using postman I get the expected invalid email or password message but with my code I get "Bad Request" no matter I try.
Here is the code that makes the request
private void Login()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://api.planet.com/");
client.DefaultRequestHeaders.Accept.Clear();
//ClientDefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
Data.User user = new Data.User
{
email = "myemail#company.com",
password = "sdosadf"
};
var requestMessage = JsonConvert.SerializeObject(user);
var content = new StringContent(requestMessage, Encoding.UTF8, "application/json");
var response = client.PostAsync("auth/v1/experimental/public/users/authenticate", content).Result;
Console.WriteLine(response.ToString());
}
catch (WebException wex )
{
MessageBox.Show(wex.Message) ;
}
}
class User
{
public string email;
public string password;
}
Here are screen grabs form Postman that are working
The way to get this to work was to alter the content header "content-type". By default HTTPClient was creating content-type: application/json;characterset= UTF8. I dropped and recreated the content header without the characterset section and it worked.
content.Headers.Remove("Content-Type");
content.Headers.Add("Content-Type", "application/json");
The issue is you are trying to call an async method without waiting for the response using await method or var task = method; task.Wait() Therefore, when you end up doing response.ToString() it returns the text you are seeing.
One way to handle this within a non-async method would be to do the following:
var task = client.PostAsync("auth/v1/experimental/public/users/authenticate", content);
task.Wait();
var responseTask = task.Content.ReadAsStringAsync();
responseTask.Wait();
Console.WriteLine(responseTask.Result);
Another way is to make the current method async by doing private async void Login() and then do:
var postResp = await client.PostAsync("auth/v1/experimental/public/users/authenticate", content);
var response = await postResp.Content.ReadAsStringAsync();
Console.WriteLine(response);
Create a Method Like this...
static async Task<string> PostURI(Uri u, HttpContent c)
{
var response = string.Empty;
var msg = "";
using (var client = new HttpClient())
{
HttpResponseMessage result = await client.PostAsync(u, c);
msg = await result.Content.ReadAsStringAsync();
if (result.IsSuccessStatusCode)
{
response = result.StatusCode.ToString();
}
}
return response;
}
call In your Method
public void Login()
{
string postData ="{\"email\":\"your_email\",\"password\":\"your_password\"}";
Uri u = new Uri("yoururl");
var payload = postData;
HttpContent c = new StringContent(payload, Encoding.UTF8,"application/json");
var t = Task.Run(() => PostURI(u, c));
t.Wait();
Response.Write(t.Result);
}

HttpClient.SendAsync method exits without throwing exception

I am calling the following function to get access token for retrieving Twitter user profile using REST Api.
public async Task<string> GetAccessToken()
{
try
{
var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.twitter.com/oauth2/token ");
var customerInfo = Convert.ToBase64String(new UTF8Encoding().GetBytes(OAuthConsumerKey + ":" + OAuthConsumerSecret));
request.Headers.Add("Authorization", "Basic " + customerInfo);
request.Content = new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded");
//program exits at this point
HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false);
string json = await response.Content.ReadAsStringAsync();
var serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(json);
return item["access_token"];
}
catch (Exception ex)
{
MessageBox.Show("In Retrieving access token : " + ex.ToString());
}
}
The program exits/terminates without retrieving a response at the point HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false); is called.
This is the parent function which calls GetAccessToken()
public async Task getUserProfile(string userName)
{
try
{
if (accessToken == null)
{
accessToken = await GetAccessToken().ConfigureAwait(false);
}
var request = new HttpRequestMessage(HttpMethod.Get, string.Format(" https://api.twitter.com/1.1/users/show.json?screen_name={0}", userName));
request.Headers.Add("Authorization", "Bearer " + accessToken);
var httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false);
var jsonString = await response.Content.ReadAsStringAsync();
var serializer = new JavaScriptSerializer();
dynamic jsonObj = serializer.Deserialize<object>(jsonString);
}
catch (Exception ex)
{
if (DEBUG)
{
MessageBox.Show("In Retrieving user profile from twitter : " + ex.ToString());
}
}
}
I am unable to catch an exception as to why the program exits at GetAccessToken() or getUserProfile(). But the code executes successfully and retrieves an HttpResponseMessage if getUserProfile() has Task<IEnumerable<string>> as return type. Why does this problem occur? How can the exception be caught?
Your application exits permaturely because you are not waiting for getUserProfile() to be completed. You can mark getTwitterInfo as async similar to the others or tell it to wait for the task to finish
public async Task getTwitterInfo() {
var twitter = new Twitter("consumerKey","consumerSecret");
await twitter.getUserProfile(userName);
}
OR
public void getTwitterInfo() {
var twitter = new Twitter("consumerKey","consumerSecret");
var task = twitter.getUserProfile(userName);
var result = task.WaitAndUnwrapException();
}
Have you tried
HttpResponseMessage response = httpClient.SendAsync(request).Result;
I have the same problem in my own code and this seems to have fixed it, should be equivalent to the original call. I still don't understand the root cause of the crash, though.

How to return a string from async

My method is calling a web service and working asynchronusly.
When getting response, everything works fine and I am getting my response.
The problem starts when I need to return this response.
here is the code of my method:
public async Task<string> sendWithHttpClient(string requestUrl, string json)
{
try
{
Uri requestUri = new Uri(requestUrl);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
...//adding things to header and creating requestcontent
var response = await client.PostAsync(requestUri, requestContent);
if (response.IsSuccessStatusCode)
{
Debug.WriteLine("Success");
HttpContent stream = response.Content;
//Task<string> data = stream.ReadAsStringAsync();
var data = await stream.ReadAsStringAsync();
Debug.WriteLine("data len: " + data.Length);
Debug.WriteLine("data: " + data);
return data;
}
else
{
Debug.WriteLine("Unsuccessful!");
Debug.WriteLine("response.StatusCode: " + response.StatusCode);
Debug.WriteLine("response.ReasonPhrase: " + response.ReasonPhrase);
HttpContent stream = response.Content;
var data = await stream.ReadAsStringAsync();
return data;
}
}
}
catch (Exception ex)
{
Debug.WriteLine("ex: " + ex.Message);
return null;
}
and I am calling it this way:
Task <string> result = wsUtils.sendWithHttpClient(fullReq, "");
Debug.WriteLine("result:: " + result);
but when printing result I am seeing something like this: System.Threading.Tasks.Task
how can I get the result string as I did with data inside my method.
You need to do this since you are calling the async method synchronously:
Task<string> result = wsUtils.sendWithHttpClient(fullReq, "");
Debug.WriteLine("result:: " + result.Result); // Call the Result
Think of the Task<string> return type as a 'promise' to return a value in the future.
If you called the async method asynchronously then it would be like the following:
string result = await wsUtils.sendWithHttpClient(fullReq, "");
Debug.WriteLine("result:: " + result);
An asynchronous method returns a task, representing a future value. In order to get the actual value wrapped in that task, you should await it:
string result = await wsUtils.sendWithHttpClient(fullReq, "");
Debug.WriteLine("result:: " + result);
Note that this will require your calling method to be asynchronous. This is both natural and correct.

Categories