How to get body content in a http client call? - c#

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;

Related

HttpRequst with parameters not workign

I am trying to make post request which works one way but other not.
Here is example how it works:
HttpClient client = new HttpClient();
string baseUrl = "https://192.168.56.1:45456/User/GetToken";
var response = await client.PostAsync(baseUrl + "?username=*******&password=****", null);
but then when I try adding it "normal way" at the endpoint i am getting nulls.
Here is how I try doing it:
HttpClient client = new HttpClient();
string baseUrl = "https://192.168.56.1:45456/User/GetToken";
Dictionary<string, string> parameters = new Dictionary<string, string>() { { "username", "ALEKS13" }, { "password", "asd" } };
FormUrlEncodedContent encodedParameters = new FormUrlEncodedContent(parameters);
var response = await client.PostAsync(baseUrl, encodedParameters);
What am I doing wrong in second code?
Here is receiving code:
[HttpPost]
[Route("/User/GetToken")]
public async Task<IActionResult> GetToken(string username, string password)
{
return await Task.Run<IActionResult>(() =>
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return StatusCode(400);
Models.User user = Models.User.Get(username);
if (user.ValidatePassword(password))
return StatusCode(200, APIAuthorization.GenerateToken(username));
return StatusCode(403);
});
}

Very slow HttpClient SendAsync call

After reading other answers I can't realize why SendAsync is so slow.
Calling same endpoint from Postman, I got a response in 160ms.
Calling from the code below, takes 10 seconds. I'm using a c# desktop application to make the call.
public static async Task<string> GetToken()
{
var url = "....";
var dict = new Dictionary<string, string>();
dict.Add("username", "foo");
dict.Add("password", "bar");
using (var client = new HttpClient(
new HttpClientHandler
{
Proxy = null,
UseProxy = false
}))
{
//bypass SSL
ServicePointManager.ServerCertificateValidationCallback = new
RemoteCertificateValidationCallback
(
delegate { return true; }
);
var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = new FormUrlEncodedContent(dict) };
var res = await client.SendAsync(req); //10 seconds here!
if (res.StatusCode != HttpStatusCode.OK)
return string.Empty;
var token = await JsonConvert.DeserializeObject<TokenResponse>(res.Content.ReadAsStringAsync());
return token.access_token;
}
}
Your code is tangled and ignores IDisposable and this: HttpClient is intended to be instantiated once per application, rather than per-use.
Make reusable method for other-type requests
private static readonly HttpClient client = new HttpClient();
private async Task<T> PostDataAsync<T>(string url, Dictionary<string, string> formData)
{
using (HttpContent content = new FormUrlEncodedContent(formData))
using (HttpResponseMessage response = await client.PostAsync(url, content).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode(); // throws if 404, 500, etc.
string responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(responseText);
}
}
Usage
public static async Task<string> GetToken()
{
var url = "....";
var dict = new Dictionary<string, string>();
dict.Add("username", "foo");
dict.Add("password", "bar");
try
{
TokenResponse token = await PostDataAsync<TokenResponse>(url, dict);
return token.access_token;
}
catch (HttpRequestException ex)
{
// handle Exception here
return string.Empty;
}
}

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);
}

call REST API in xamarin

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));

convert task<string> to string [duplicate]

This question already has answers here:
How can I call async method from constructor?
(5 answers)
Closed 2 years ago.
I want to parse from a JSON file in a universal windows phone application but I can't convert task to string
public MainPage()
{
this.InitializeComponent();
HttpClient httpClient = new HttpClient();
String responseLine;
JObject o;
try
{
string responseBodyAsText;
HttpResponseMessage response = httpClient.GetAsync("http://localhost/list.php").Result;
//response = await client.PostAsync(url, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
responseBodyAsText = response.Content.ReadAsStringAsync().Result;
// responseLine = responseBodyAsText;
string Website = "http://localhost/list.php";
Task<string> datatask = httpClient.GetStringAsync(new Uri(string.Format(Website, DateTime.UtcNow.Ticks)));
string data = await datatask;
o = JObject.Parse(data);
Debug.WriteLine("firstname:" + o["id"][0]);
}
catch (HttpRequestException hre)
{
}
I have error in this line
string data = await datatask;
how can I fix it?
Looking into this documentation, you can get that using: Result property.
For Example:
Task<int> task1 = myAsyncMethod(); //You can also use var instead of Task<int>
int i = task1.Result;
You cannot use await inside a constructor. You'll need to create an async method for that.
Generally I don't recommend using async void, but when you're calling it from the constructor it's somewhat justified.
public MainPage()
{
this.InitializeComponent();
this.LoadContents();
}
private async void LoadContents()
{
HttpClient httpClient = new HttpClient();
String responseLine;
JObject o;
try
{
string responseBodyAsText;
HttpResponseMessage response = await httpClient.GetAsync("http://localhost/list.php");
//response = await client.PostAsync(url, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
responseBodyAsText = await response.Content.ReadAsStringAsync();
// responseLine = responseBodyAsText;
string Website = "http://localhost/list.php";
Task<string> datatask = httpClient.GetStringAsync(new Uri(string.Format(Website, DateTime.UtcNow.Ticks)));
string data = await datatask;
o = JObject.Parse(data);
Debug.WriteLine("firstname:" + o["id"][0]);
}
catch (HttpRequestException hre)
{
// You might want to actually handle the exception
// instead of silently swallowing it.
}
}
Try this:
Task<string> post = postPostAsync("Url", data).Result.Content.ReadAsStringAsync();
post.Result.ToString();

Categories