Make http client synchronous: wait for response - c#

I have some file to upload and some of the files failed because the post is asynchronous and not synchronous..
I'm trying to make this call as synchronized call..
I want to wait for the response.
How can I make this call as synchronous?
static async Task<JObect> Upload(string key, string url, string
sourceFile, string targetFormat)
{
using (HttpClientHandler handler = new HttpClientHandler {
Credentials = new NetworkCredential(key, "")
})
using (HttpClient client = new HttpClient(handler))
{
var request = new MultipartFormDataContent();
request.Add(new StringContent(targetFormat), "target_format");
request.Add(new StreamContent(File.OpenRead(sourceFile)),
"source_file",
new FileInfo(sourceFile).Name);
using (HttpResponseMessage response = await client.PostAsync(url,
request).ConfigureAwait(false))
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync().ConfigureAwait(false);
return JsonObject.Parse(data);
}
}
}
Any help appreciated!

change
await content.ReadAsStringAsync().ConfigureAwait(false)
to
content.ReadAsStringAsync().Result
the ReadAsStringAsync returns a Task object. the '.Result' in the end of the line tell the compiler to return the inner string.

That should do it:
static async Task<JObect> Upload(string key, string url, string
sourceFile, string targetFormat)
{
using (HttpClientHandler handler = new HttpClientHandler {
Credentials = new NetworkCredential(key, "")
})
using (HttpClient client = new HttpClient(handler))
{
var request = new MultipartFormDataContent();
request.Add(new StringContent(targetFormat), "target_format");
request.Add(new StreamContent(File.OpenRead(sourceFile)),
"source_file",
new FileInfo(sourceFile).Name);
using (HttpResponseMessage response = await client.PostAsync(url,request))
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
return JsonObject.Parse(data);
}
}
}

Related

httpClient Does not give Response

i am trying to call the Zoom Api for Access token. It work Perfectly fine when i am trying to post with postman .
but from code it does not respond
ZoomApiLink_StepNo2
below are the following details
public static async Task<String> PostTogetToken<T>(string requestUrl, string client_Secretkey) {
ZoomToken hello = new ZoomToken();
var EncodedURl = ApiService.Base64Encode(client_Secretkey);
using (var _httpClient = new HttpClient()) {
if (!string.IsNullOrEmpty(requestUrl))
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Basic " + EncodedURl);
var httpContent = new StringContent("", System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(requestUrl)) {
Version = HttpVersion.Version11,
Content = httpContent
};
using (var response = await _httpClient.SendAsync(httpRequestMessage)) {
if (response.IsSuccessStatusCode) {
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
} else {
return await response.Content.ReadAsStringAsync();
}
}
}
}
You're seeing a common deadlock problem because code further up the stack is using Result, blocking on asynchronous code.
To fix, change the Result to await and use async all the way.

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

postAsync with header and content c#

I need to postAsync with header and content together. In order to get access to a website through Console Application in C#. I have my headers as an HttpHeader object with variable name header and my content named newContent as a string object with __Token, return, Email and Password. Now what I want to do is add newContent to header and then use postAsync(url, header+content) to make my POST request.
public async static void DownloadPage(string url)
{
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (HttpClient client = new HttpClient(handler))
{
using (HttpResponseMessage response = client.GetAsync(url).Result)
{
//statusCode
CheckStatusCode(response);
//header
HttpHeaders headers = response.Headers;
//content
HttpContent content = response.Content;
//getRequestVerificationToken&createCollection
string newcontent = CreateCollection(content);
using(HttpResponseMessage response2 = client.PostAsync(url,))
}
}
}
public static string GenerateQueryString(NameValueCollection collection)
{
var array = (from key in collection.AllKeys
from value in collection.GetValues(key)
select string.Format("{0}={1}", WebUtility.UrlEncode(key), WebUtility.UrlEncode(value))).ToArray();
return string.Join("&", array);
}
public static void CheckStatusCode(HttpResponseMessage response)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.ReasonPhrase));
else
Console.WriteLine("200");
}
public static string CreateCollection(HttpContent content)
{
var myContent = content.ReadAsStringAsync().Result;
HtmlNode.ElementsFlags.Remove("form");
string html = myContent;
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var input = doc.DocumentNode.SelectSingleNode("//*[#name='__Token']");
var token = input.Attributes["value"].Value;
//add all necessary component to collection
NameValueCollection collection = new NameValueCollection();
collection.Add("__Token", token);
collection.Add("return", "");
collection.Add("Email", "11111111#hotmail.com");
collection.Add("Password", "1234");
var newCollection = GenerateQueryString(collection);
return newCollection;
}
I did the very same thing yesterday. I created a seperate class for my Console App and put the HttpClient stuff in there.
In Main:
_httpCode = theClient.Post(_response, theClient.auth_bearer_token);
In the class:
public long Post_RedeemVoucher(Response _response, string token)
{
string client_URL_voucher_redeem = "https://myurl";
string body = "mypostBody";
Task<Response> content = Post(null, client_URL_voucher_redeem, token, body);
if (content.Exception == null)
{
return 200;
}
else
return -1;
}
Then the call itself:
async Task<Response> Post(string headers, string URL, string token, string body)
{
Response _response = new Response();
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, URL);
request.Content = new StringContent(body);
using (HttpResponseMessage response = await client.SendAsync(request))
{
if (!response.IsSuccessStatusCode)
{
_response.error = response.ReasonPhrase;
_response.statusCode = response.StatusCode;
return _response;
}
_response.statusCode = response.StatusCode;
_response.httpCode = (long)response.StatusCode;
using (HttpContent content = response.Content)
{
_response.JSON = await content.ReadAsStringAsync().ConfigureAwait(false);
return _response;
}
}
}
}
catch (Exception ex)
{
_response.ex = ex;
return _response;
}
}
I hope this points you in he right direction!
How about iterating over your Headers and adding them to the Content object:
var content = new StringContent(requestString, Encoding.UTF8);
// Iterate over current headers, as you can't set `Headers` property, only `.Add()` to the object.
foreach (var header in httpHeaders) {
content.Headers.Add(header.Key, header.Value.ToString());
}
response = client.PostAsync(Url, content).Result;
Now, they're sent in one method.
If you are still looking into this you can also add headers at the request level as well as the HttpClient level. This works for me:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, URL);
request.Content = new StringContent(body);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

Upload file to Pushbullet in Windows 10 app c#

I'm currently using Pushbullet API and need to upload a file.
I can successfully get an upload url as specified in the docs using this method:
public static async Task<Uploads> GetUploadUrl(string file_name, string file_type)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var json = new JObject
{
["file_name"] = file_name,
["file_type"] = file_type
};
var result = await client.PostAsync(new Uri(_uploadUrl, UriKind.RelativeOrAbsolute), new HttpStringContent(json.ToString(), UnicodeEncoding.Utf8, "application/json"));
if (result.IsSuccessStatusCode)
{
var textresult = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Uploads>(textresult);
}
}
return null;
}
The problem is when I try to upload the file. I'm currently using this method:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent);
}
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
but I get a Http 400 error. What's the right way to upload a file using multipart/form-data in a UWP app?
HTTP 400 error indicates Bad Request, it means the request could not be understood by the server due to malformed syntax. In the other word, the request sent by the client doesn't follow server's rules.
Let's look at the document, and we can find in the example request it uses following parameter:
-F file=#cat.jpg
So in the request, we need to set the name for the uploaded file and the name should be "file". Besides, in this request, there is no need to use access token. So you can change your code like following:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent, "file");
}
//client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
Then your code should be able to work. You will get a 204 No Content response and UploadFile method will return true.

How to send image in HttpClient SendRequestAsync

I am using Windows.Web.Http instead of System and I am trying to send an image.
My sample code:
Dictionary<string, object> requestDictionary;
HttpClient httpClient = new HttpClient();
HttpRequestMessage re = new HttpRequestMessage();
HttpResponseMessage response;
re.Method = HttpMethod.Post;
re.RequestUri = url;
string content_type = "application/json";
string req_data = JsonConvert.SerializeObject(requestDictionary);
re.Content = new HttpStringContent(req_data, UnicodeEncoding.Utf8, content_type);
response = await httpClient.SendRequestAsync(re);
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
httpClient.Dispose();
httpClient=null;
In this case my requestDictionary will be some thing like
requestDictionary.Add("Image", filename);
requestDictionary.Add("description", some_description);
Someone please help me to achieve this.
By using .Net 4.5 (or by adding the Microsoft.Net.Http package from NuGet) there is an easier way to do this:
private string Upload(string actionUrl, string paramString, byte[] paramFileBytes)
{
HttpContent stringContent = new StringContent(paramString);
HttpContent bytesContent = new ByteArrayContent(paramFileBytes);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "paramter");
formData.Add(bytesContent, "image");
var response = client.PostAsync(actionUrl, formData).Result;
if (!response.IsSuccessStatusCode)
{
return null;
}
return response.Content.ReadAsStringAsync().Result;
}
}
If you prefer to use a stream instead of a byte-array you can easily do this, by just using new StreamContent() instead of new ByteArrayContent().

Categories