How can I translate Webrequest method in HttpClient - c#

I have this code for recovering Http code and description, but Visual Studio says that WebRequest is obsolete and that I have to use HttpClient. I'm not familiar with HttpClient can you help me?
IConfigurationRoot config;
myRequest = WebRequest.CreateHttp($"{config["BASE_URL"]}{link}");
myResponse = (HttpWebResponse)myRequest.GetResponse();
Check_load($"{config["BASE_URL"]}{link}");
var code = ((int)myResponse.StatusCode);
var desc = myResponse.StatusDescription;

var client = new HttpClient();
var response = await client.GetAsync(url);
var statusCode = response.StatusCode;
var content = response.Content;
if(statusCode != HttpStatusCode.OK && statusCode != HttpStatusCode.Created){
//return something, error, description
}
Update
From comment #Charlieface pointed out where I haven't declared HttpClient as static field. To avoid creating instances of HttpClient every time it is called, the complete workground as below.
public class HttpHelper{
private static HttpClent client = new HttpClient();
public static async Task<string> GetAsync(string url)
{
var response = await client.GetAsync(url);
var statusCode = response.StatusCode;
var content = response.Content;
if(statusCode != HttpStatusCode.OK && statusCode != HttpStatusCode.Created)
{
//return something, error, description
//return $"error with status code: {statusCode}";
}
else
{
//return "success";
}
}
}

The use of HttpClient is very simple. See the code below
try
{
using (HttpClient client = new HttpClient())
{
var res = await client.GetAsync(url);
var response = await res.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<MyObject>(response);
// use the new data retreived...
}
}
catch (Exception)
{
responseMessage = new BadRequestObjectResult("error retreiving data");
}
This suppose your data are sent in JSON format

Related

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

Xamarin POST method not returning correct value

I am having a problem with sending a POST request and getting a response. I have made local PHP script which returns some string values, and I can't get it to work with Xamarin.
This is the method I am using for to send the request:
public async Task<string> Post_Request()
{
var request = new HttpRequestMessage();
request.RequestUri = new Uri("http://localhost/server.php");
request.Method = HttpMethod.Post;
request.Headers.Add("Accept", "application/json");
var client = new HttpClient();
HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(continueOnCapturedContext: false);
if (response.StatusCode == HttpStatusCode.OK)
{
return "OK";
}
else
{
return "BAD!";
}
}
When debbuging, the program does not go into the if or else code branches on the "if (response.StatusCode == HttpStatusCode.OK)" condition.
This is my PHP script:
<?php
return
"
{
"user":"01",
"name":"ime"
}
"
//echo "OK";
?>
This is a sample post request that I have used.
var objRequest = new CustomerDetailsRequest() {
customerId = 1
};
string url = $"/api/v1/CustomerDetails";
var requestBody = await Task.Run(() => JsonConvert.SerializeObject(objRequest));
using (var httpClient = new HttpClient())
{
CustomerDetailsResponse data = new CustomerDetailsResponse();
try
{
httpClient.BaseAddress = new Uri("http://localhost:3000");
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
var result = await httpClient.PostAsync(url, content);
var response = await result.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<CustomerDetailsResponse>(response);
if (result.IsSuccessStatusCode && result.StatusCode == HttpStatusCode.OK)
{
return data;
}
return null;
}
catch (Exception exp)
{
return null;
}
}
Let me know if this is confusing

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

Handling http response codes in GetStringAsync

i'm very new to C#, let alone Windows Phone development :)
I'm trying to send a request, get the JSON response, but if there is an error (such as 401), be able to tell the user such. Here is my code:
async Task<string> AccessTheWebAsync()
{
//builds the credentials for the web request
var credentials = new NetworkCredential(globalvars.username, globalvars.password);
var handler = new HttpClientHandler { Credentials = credentials };
//calls the web request, stores and returns JSON content
HttpClient client = new HttpClient(handler);
Task<string> getStringTask = client.GetStringAsync("https://www.bla.com/content");
String urlContents = await getStringTask;
return urlContents;
}
I know it must be something I'm doing wrong in the way that I send the request and store the response...but i'm just not sure what.
If there is an error, I get a general:
net_http_message_not_success_statuscode
Thank you!
You could use te GetAsync() method instead of the GetStringAsync().
HttpResponseMessage response = await client.GetAsync("https://www.bla.com/content");
if(!response.IsSuccessStatusCode)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
do something...
}
}
String urlContents = await response.Content.ReadAsStringAsync();
This way you can make use of the HttpStatusCode enumerable to check the returned status code.
Instead of using an HttpClient use a plain good old HttpWebRequest :)
async Task<string> AccessTheWebAsync()
{
HttpWebRequest req = WebRequest.CreateHttp("http://example.com/nodocument.html");
req.Method = "GET";
req.Timeout = 10000;
req.KeepAlive = true;
string content = null;
HttpStatusCode code = HttpStatusCode.OK;
try
{
using (HttpWebResponse response = (HttpWebResponse)await req.GetResponseAsync())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
content = await sr.ReadToEndAsync();
code = response.StatusCode;
}
}
catch (WebException ex)
{
using (HttpWebResponse response = (HttpWebResponse)ex.Response)
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
content = sr.ReadToEnd();
code = response.StatusCode;
}
}
//Here you have now content and code.
return content;
}

Receiving JSON data back from HTTP request

I have a web request that is working properly, but it is just returning the status OK, but I need the object I am asking for it to return. I am not sure how to get the json value I am requesting. I am new to using the object HttpClient, is there a property I am missing out on? I really need the returning object. Thanks for any help
Making the call - runs fine returns the status OK.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseMsg = client.GetAsync(string.Format("http://localhost:5057/api/Photo")).Result;
The api get method
//Cut out alot of code but you get the idea
public string Get()
{
return JsonConvert.SerializeObject(returnedPhoto);
}
If you are referring to the System.Net.HttpClient in .NET 4.5, you can get the content returned by GetAsync using the HttpResponseMessage.Content property as an HttpContent-derived object. You can then read the contents to a string using the HttpContent.ReadAsStringAsync method or as a stream using the ReadAsStreamAsync method.
The HttpClient class documentation includes this example:
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Building on #Panagiotis Kanavos' answer, here's a working method as example which will also return the response as an object instead of a string:
using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json; // Nuget Package
public static async Task<object> PostCallAPI(string url, object jsonObject)
{
try
{
using (HttpClient client = new HttpClient())
{
var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<object>(jsonString);
}
}
}
catch (Exception ex)
{
myCustomLogger.LogException(ex);
}
return null;
}
Keep in mind that this is only an example and that you'd probably would like to use HttpClient as a shared instance instead of using it in a using-clause.
Install this nuget package from Microsoft System.Net.Http.Json. It contains extension methods.
Then add using System.Net.Http.Json
Now, you'll be able to see these methods:
So you can now do this:
await httpClient.GetFromJsonAsync<IList<WeatherForecast>>("weatherforecast");
Source: https://www.stevejgordon.co.uk/sending-and-receiving-json-using-httpclient-with-system-net-http-json
I think the shortest way is:
var client = new HttpClient();
string reqUrl = $"http://myhost.mydomain.com/api/products/{ProdId}";
var prodResp = await client.GetAsync(reqUrl);
if (!prodResp.IsSuccessStatusCode){
FailRequirement();
}
var prods = await prodResp.Content.ReadAsAsync<Products>();
What I normally do, similar to answer one:
var response = await httpClient.GetAsync(completeURL); // http://192.168.0.1:915/api/Controller/Object
if (response.IsSuccessStatusCode == true)
{
string res = await response.Content.ReadAsStringAsync();
var content = Json.Deserialize<Model>(res);
// do whatever you need with the JSON which is in 'content'
// ex: int id = content.Id;
Navigate();
return true;
}
else
{
await JSRuntime.Current.InvokeAsync<string>("alert", "Warning, the credentials you have entered are incorrect.");
return false;
}
Where 'model' is your C# model class.
It's working fine for me by the following way -
public async Task<object> TestMethod(TestModel model)
{
try
{
var apicallObject = new
{
Id= model.Id,
name= model.Name
};
if (apicallObject != null)
{
var bodyContent = JsonConvert.SerializeObject(apicallObject);
using (HttpClient client = new HttpClient())
{
var content = new StringContent(bodyContent.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Add("access-token", _token); // _token = access token
var response = await client.PostAsync(_url, content); // _url =api endpoint url
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
try
{
var result = JsonConvert.DeserializeObject<TestModel2>(jsonString); // TestModel2 = deserialize object
}
catch (Exception e){
//msg
throw e;
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
return null;
}
The code below is to access your HttpResponseMessage and extract your response from HttpContent.
string result = ret.Result.Content.ReadAsStringAsync().Result;
Convert your json in a structure according with your business
In my case BatchPDF is a complex object that it is being populated by result variable.
BatchPDF batchJson = JsonConvert.DeserializeObject<BatchPDF>(result);
return batchJson;

Categories