I am trying to write the following code using HttpClient and async, but it's not able return data.
WebRequest request = WebRequest.Create("some_url");
request.Headers.Add("cookie", "some_cookie");
Stream objStream = request.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(objStream);
string sLine = "";
int i = 0;
while (sLine != null)
{
i++;
sLine = objReader.ReadLine();
if (sLine != null)
Console.WriteLine(sLine);
}
Here is what I tried.
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("cookie", "some_cookie");
using (var response = await client.GetAsync("some_url"))
{
string responseData = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseData);
}
}
Any help will be appreciated.
Edit: Here is the code that works for me using HttpClient.
var baseAddress = new Uri(baseUrl);
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, queryString);
requestMessage.Headers.Add("cookie", cookie);
var response = client.SendAsync(requestMessage);
response.Wait();
var content = response.Result.Content.ReadAsStringAsync();
content.Wait();
Console.WriteLine(content.Result);
}
Thanks for all the help.
You are doing the async and await, but you are not waiting for response data to be returned or reached so the following snippet will do the job :
Try this code :
static async Task<string> HttpGetResponse()
{
WebRequest request = WebRequest.Create("some_url");
request.Headers.Add("cookie", "some_cookie");
string responseData;
Stream objStream = request.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(objStream);
string sLine = "";
int i = 0;
while (sLine != null)
{
i++;
sLine = objReader.ReadLine();
if (sLine != null)
Console.WriteLine(sLine);
}
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("cookie", "some_cookie");
using (var response = await client.GetAsync("some_url"))
{
responseData = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseData);
}
}
return responseData;
}
in main call it like this :
static void Main(string[] args)
{
Task<string> t = HttpGetResponse();
//Do alot of work
t.Wait();
string response = t.Result;
Console.WriteLine(response);
}
Hope this was useful.
Related
I have designed the following method to call api within the loop. I was wondering if there is any other better way (performance) of calling APIs multiple times?
private List<ClientInfo> populateDetails(List<ClientInfo> lstClientDetails)
{
using (var client = new HttpClient())
{
client.BaseAddress = EndpointAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string Uri = "";
ClientInfo clientInfo;
foreach (var record in lstClientDetails)
{
Uri = string.Format("{0}", record.id);
var postResponse = client.GetAsync(Uri).Result;
if (postResponse.IsSuccessStatusCode)
{
string result = postResponse.Content.ReadAsStringAsync().Result;
clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);
if (clientInfo != null)
record.email = clientInfo.email;
}
}
return lstClientDetails;
}
}
Maybe you can change your code to use async/await pattern
private async Task populateDetails(List<ClientInfo> lstClientDetails)
{
using (var client = new HttpClient())
{
client.BaseAddress = EndpointAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string Uri = "";
ClientInfo clientInfo;
foreach (var record in lstClientDetails)
{
Uri = string.Format("{0}", record.id);
var postResponse = await client.GetAsync(Uri);
if (postResponse.IsSuccessStatusCode)
{
string result = await postResponse.Content.ReadAsStringAsync();
clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);
if (clientInfo != null)
record.email = clientInfo.email;
}
}
}
}
And as you can see it doesn't make senso to return the same List which is passed as a paramters: the code will change the underlyne objects
Reference Microsoft Docs Parallel Library
sample code:
public class ParallelClient
{
private async Task ParallelRequest(List<string> requests)
{
var responses = new ConcurrentBag<HttpResponseMessage>();
using (var client = new HttpClient())
{
Parallel.ForEach(requests, new ParallelOptions { MaxDegreeOfParallelism = 10 }, async r =>
{
var requestMessage = new HttpRequestMessage();
requestMessage.Method = HttpMethod.Post;
requestMessage.Content = new StringContent(r, Encoding.UTF8, "application/json");
var response = await client.SendAsync(requestMessage);
responses.Add(response);
});
}
}
}
I have this working Xunit code.
[Fact]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail()
{
using (var client = new HttpClient())
{
var filePath = #"D:\Files\test.pdf";
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
But the above only test for one scenario. How do I use XUnit InlineData so that I can insert multiple test data for MultipartFormDataContent?
[Theory]
[InlineData(MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf")]
[InlineData(MediaTypeNames.Application.Xml, #"D:\Files\test.xml")]
// else files what you need
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
OR
[Theory]
[MemberData(nameof(TestGenerator.GetTestData), MemberType = typeof(TestGenerator))]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
class TestGenerator
{
public static IEnumerable<object[]> GetTestData() => new List<object[]>
{
new object[] { MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf" },
new object[] { MediaTypeNames.Application.Xml, #"D:\Files\test.xml" }
};
}
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");
I am doing post and get response using HttpClient to communicate with REST API as below:
public static string PostToAPI( string value)
{
var payload = new APIModel
{
CommandText = value
};
var stringPayload = JsonConvert.SerializeObject(payload);
var httpContent = new StringContent(stringPayload,Encoding.UTF8,"application/json");
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
HttpResponseMessage message=client.PostAsync("https://testAPI/test",httpContent).Result if (message.IsSuccessStatusCode)
{
string result = message.Content.ReadAsStringAsync().Result;
return result;
}
return string.Empty;
}
is there any other alternative or best way do it?
You can always use HttpWebRequest and HttpWebResponse. Try Below
try
{
var webAddr = "URL";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application";
httpWebRequest.Method = "POST";
string str = "request string";
httpWebRequest.Headers["Authorization"] = "";
httpWebRequest.Headers["TenantId"] = "";
httpWebRequest.Headers["Client-Type"] = "";
httpWebRequest.Headers["Protocol"] = "";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
Console.WriteLine(str);
streamWriter.Write(str);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Console.WriteLine("result=" + result);
}
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
}
I'm using HttpWebRequests to contact an API and need to add a header but the compiler tells me that the method does not exists.
Yet, when I check MSDN, it tells me that the method already exists.
Setting my UserAgent-property fails as well.
Can anyone help me please?
try{
HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(url);
wr.Method = "GET";
wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken));
wr.UserAgent = _appNameAndContact;
var resp = (System.Net.HttpWebResponse) await wr.BetterGetResponse();
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
{
using (var sw = new System.IO.StreamReader(resp.GetResponseStream()))
{
var msg = sw.ReadToEnd();
User usr = JsonConvert.DeserializeObject<User>(msg);
//var results = JSONHelper.Deserialize<User>(msg);
return usr;
}
}
}
You will have to use a HttpRequestMessage like this:
using (var httpClient = new HttpClient())
{
var url = new Uri("http://bing.com");
var accessToken = "1234";
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, url))
{
httpRequestMessage.Headers.Add(System.Net.HttpRequestHeader.Authorization.ToString(),
string.Format("Bearer {0}", accessToken));
httpRequestMessage.Headers.Add("User-Agent", "My user-Agent");
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
{
// do something with the response
var data = httpRequestMessage.Content;
}
}
}