This question already has answers here:
await vs Task.Wait - Deadlock?
(3 answers)
Closed 7 years ago.
I have next part of code :
using (var client = new HttpClient()) // from Windows.Web.Http;
{
//setup client
var tokenUri = new Uri(apiBaseUri + "/token");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new HttpMediaTypeWithQualityHeaderValue("application/json"));
//setup login data
IHttpContent formContent = new HttpFormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
});
//send request
HttpResponseMessage responseMessage = await client.PostAsync(tokenUri, formContent);
//get access token from response body
var responseJson = await responseMessage.Content.ReadAsStringAsync();
var jObject = JObject.Parse(responseJson);
return jObject.GetValue("access_token").ToString();
}
This makes call to my Web Api. I have checked if it's really works with fiddler - as result I can see response what i espect (Bearer token). But in code this response are never received.
What is the problem?
This:
var token = GetAPIToken(UserName, Password, ApiBaseUri).Result;
Causes a classic deadlock. You shouldn't be blocking on async code with Task.Result or Task.Wait. Instead, you need to go "async all the way" and await on it too, making the method higher up the call stack async Task as well:
public async Task GetApiTokenAsync()
{
var token = await GetAPIToken(UserName, Password, ApiBaseUri);
}
Related
I'm trying to invoke a PATCH operation on our organization's Salesforce API.
The url is correct (format - https://xxxx.salesforce.com/services/data/v43.0/sobjects/Classification__c/objectid?_HttpMethod=PATCH) and so is the JSON content, though you possibly can't guage that from the code below.
public async Task PatchSalesforceObjectAsync(string objectToPost, string objectid, HttpContent content)
{
SetupHttpClient();
using (_response = await _httpClient.PostAsync($"{_sfObjectPartialURL}{objectToPost}{objectid}?_HttpMethod=PATCH", content))
{
if (_response.IsSuccessStatusCode)
{
var x = _response.Content;
}
}
}
void SetupHttpClient()
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _sfAccesstoken);
_httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.BaseAddress = _baseURI;
}
Response - StatusCode:400, ReasonPhrase:Bad Request
I've made the exact same request through POSTMAN and it goes through fine, so I'm guessing that the issue lies with how I'm making the call in the .Net framework.
I've also tried using a HttpRequestMessage object and then call SendAsync on the HttpClient object, but that leads to the same result.
HttpRequestMessage message = new HttpRequestMessage()
{
Method = new HttpMethod("PATCH"),
RequestUri = new Uri(_baseURI, $"{_sfObjectPartialURL}{objectToPost}{objectid}"),
Content = content,
};
using (_response = await _httpClient.SendAsync(message))
{
Rookie Mistake - There was a field in the Patch that I'm not allowed to update and since I was dealing with the same object and switching between a POST and a PATCH based on whether the object already existed I was not aware of this field level restriction.
I'm trying to get a balance from coinfloor using their API,
while I was able to successfully parse their unauthenticated/public GET responses, I'm having troubles sending authenticated private POST requests with extra parameters.
Currently I get StatusCode: 401, ReasonPhrase: 'Unauthorized'
class Program
{
static HttpClient client = new HttpClient();
static void Main()
{
RunAsync().Wait();
}
static async Task RunAsync()
{
client.BaseAddress = new Uri("https://webapi.coinfloor.co.uk:8090/bist/XBT/GBP/balance/");
client.DefaultRequestHeaders.Authorization= new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "userID/apikey", "passphrase"))));
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("User ID","userid"),
new KeyValuePair<string, string>("API key","apikey"),
new KeyValuePair<string, string>("Passphrase","pass")
});
try
{
var result = await client.PostAsync("https://webapi.coinfloor.co.uk:8090/bist/XBT/GBP/balance/", content);
string resultContent = await result.Content.ReadAsStringAsync();
}
I've tried using both the default authorization headers and sending the data with FormUrlEncodedContent. their documentation says " All private API calls require authentication. You need to provide 3 parameters to authenticate a request: User ID, API key,Passphrase"
not sure what I'm doing wrong?
and how should I be sending other extra parameters in the requests?
just a note to mention that the code is actually correct, there was a mistake on my part with the various ids and passwords.
Everything works fine on Postman with x-www-from-urlencoded and basic auth. Now trying to get my hands dirty, I just get status code 200 with nothing on mailgun, no logs recorded.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://api.mailgun.net/v3");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("api", "key-withheld-till-a-verdict-has-passed");
var msg = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("from",
$"Excited User <mailgun#sandboxSOMEGUIDHERE.mailgun.org>"),
new KeyValuePair<string, string>("to","approved-to-receive#mailgun"),
new KeyValuePair<string, string>("subject", "Test Please Do Not Reply"),
new KeyValuePair<string, string>("text","Thanks for borrowing me your inbox")
};
var request = new HttpRequestMessage(HttpMethod.Post,
"sandboxSOMEGUIDHERE.mailgun.org/messages");
request.Content = new FormUrlEncodedContent(msg);
var response = await client.SendAsync(request);
// I get 200 status code
var result = await response.Content.ReadAsStringAsync();
//I get result = "Mailgun Magnificent API"
}
First, it turns out I was getting the BaseAddress not right. I had to place a slash at the end of the BaseAddress.
client.BaseAddress = new Uri("https://api.mailgun.net/v3/");
without the slash, I was posting to (note v3 is missing),
https://api.mailgun.net/sandboxSOMEGUIDHERE.mailgun.org/messages
After sorting that out, another problem emerged 401 - ANAUTHORIZED. And with the help of this SO answer I do,
var byteArray = new UTF8Encoding()
.GetBytes("api:key-withheld-till-a-verdict-has-passed");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
But the reason why mailgun was responding with Ok still remain mysterious. To investigate further, I used Postman to post to,
https://api.mailgun.net/sandboxSOMEGUIDHERE.mailgun.org/messages
and to my surprise, Mailgun mysteriously responded with Ok.
Before everyone tells me to increase the timeout values I don't want to increase it because it doesn't make sense that 100 seconds isn't long enough. All other get and post responses take less time without throwing a timeout/task cancel exception.
I am trying to mimic the following, I whited out the user and password...
Here is the code
var baseAddress = new Uri("http://www.foodservice.com/home/fs_login.cfm?logmode=Home");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var trypage = await client.GetAsync("http://www.foodservice.com/home/fs_login.cfm?logmode=Home");
trypage.EnsureSuccessStatusCode();
Console.WriteLine("something");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("user_name", "someuser"),
new KeyValuePair<string, string>("password", "somepass"),
new KeyValuePair<string, string>("logmode", "Home")
});
var result = await client.PostAsync("http://www.foodservice.com/home/fs_login_check.cfm", content);
Console.WriteLine("somethingelse");
result.EnsureSuccessStatusCode();
It hands on. something prints, somethingelse doesn't
var result = await client.PostAsync("http://www.foodservice.com/home/fs_login_check.cfm", content);
I don't see any reason why it should hang and fail here...
Summary: Why isn't my post getting through? I am I using the wrong address or something?
Try this
await client.GetAsync("http://www.foodservice.com/home/fs_login.cfm?logmode=Home").ConfigureAwait(false);
and
await client.PostAsync("http://www.foodservice.com/home/fs_login_check.cfm", content).ConfigureAwait(false);
you can get more information on Httpclient Async call
For some reason the process could not be multithreaded.
Switched from Tasks to blocking single threaded it worked fine...
im using PostAsync to call my external webAPI programatically in my back end.
I have had the method working using a httpget, however turning it into a post seems more problematic, due to the httpcontent object required. when awaiting, the status code is always a 404 due to the data not being passed over.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:52715/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var data = JsonConvert.SerializeObject(new { user = "JOHNSMITH" });
HttpResponseMessage response = await client.PostAsync("MessageUser", new StringContent(data, Encoding.UTF8, "text/json"));
if (response.IsSuccessStatusCode)
{
Console.WriteLine("\n sent signal to dept");
}
}