Asynchronous HTTP Response Message - c#

so this has been bugging since a while. I am not sure why my Http Response Message step is skipped by Visual Studio Debugger. This is the code i have currently:
public async void APIcall()
{
HttpClient httpClient = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://xxxx");
requestMessage.Headers.Add("Accept", "application/json");
requestMessage.Headers.Add("ContentType", "application/json");
requestMessage.Headers.Add("RequestMessageGUID", "xxxxxx");
HttpResponseMessage response = await httpClient.SendAsync(requestMessage);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
Console.ReadLine();
}
Please give your suggestions and help to resolve this.

First, you should avoid doing async on void methods unless it's an event handler. Use Task even if you are not returning anything.
Next you are assuming that you will always get content from your request.
You should check first that there is something to get
When you use async on void methods your exceptions are not going to get caught. That is probably why it kept skipping as you said. It was probably error out.
private static HttpClient httpClient = new HttpClient();
public async Task APIcall() {
try {
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://xxxx");
requestMessage.Headers.Add("Accept", "application/json");
requestMessage.Headers.Add("ContentType", "application/json");
requestMessage.Headers.Add("RequestMessageGUID", "xxxxxx");
HttpResponseMessage response = await httpClient.SendAsync(requestMessage);
if (response.Content.Headers.ContentLength.GetValueOrDefault() > 0) {
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
} else {
Console.WriteLine(response.StatusCode);
}
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}

Related

HttpClient.PostAsJsonAsync crushed without exception

I am trying to call an api(POST method) with HttpClient.PostAsJsonAsync. However, it stopped at httpClient.PostAsJsonAsync without any exception.
The source code as below:
public static async Task<oResult> PostApi(string JSON_sObject, string sEnd_Url) {
oResult oResult = new oResult();
var Data = JsonConvert.DeserializeObject(JSON_sObject);
var Url = "http://localhost:44340/" + sEnd_Url;
HttpClient httpClient = new HttpClient();
try {
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await httpClient.PostAsJsonAsync(new Uri(Url), Data); // it stopped here
if (response.IsSuccessStatusCode)
{
var sResponse_content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<oResult>(sResponse_content);
}
else
{
return oResult;
}
}
catch (Exception ex)
{
LogFile(ex);
return oResult;
}
}
Please advice me if any issue from the source code.
Thank you
you should not trying serialize deserialize twice
remove from your code
var Data = JsonConvert.DeserializeObject(JSON_sObject);
and replace
HttpResponseMessage response = await httpClient.PostAsJsonAsync(new Uri(Url), Data);
with this
var content = new StringContent(JSON_sObject, Encoding.UTF8, "application/json");
var response = await client.PostAsync(sEnd_Url, content);
also fix base httpclient address
var baseUri= #"http://localhost:44340";
using HttpClient client = new HttpClient { BaseAddress = new Uri(baseUri) };
try {

Prepare controller and http request to preocess request without returning value

I have following method to get collection of cars:
public async Task<IEnumerable<Car>> GetCars(object car, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/GetCars");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(car), Encoding.UTF8, "application/json");
var req = await httpClient.PostAsync(uri, content, ct);
var response = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<Car>>(response);
}
}
In my service api in controller i have this to get it:
[HttpPost]
[Route("api/[controller]/[action]")]
public IActionResult GetBottleTypeById(Car car)
{
return Ok(_carQuery.GetCars(car));
}
Both things works great - no issues.
Now i need to save the Car and i don't need to return something (eventually i could return true or false whether it was succesfull or not). The problem is i am not sure how controller's method should look like, if i do this way it says: not all code path returns value:
[HttpPost]
[Route("api/[controller]/[action]")]
public IActionResult UpdateOperation(Car car)
{
_carRepository.UpdateOperation(car) //UpdateOperation is void with try/catch - throw;
}
Same thing with request, how this should be accomplished?
public async Task UpdateCar(Car selectedCar, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/UpdateOperation");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(selectedCar), Encoding.UTF8, "application/json");
var req = await httpClient.PostAsync(uri, content, ct);
var response = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<Car>>(response);
}
}
How could i prepare both things to make it work?
Just change your code to return void. ASP.NET is smart enough to just send 200 OK if no exceptions were thrown out of a void method.
[HttpPost]
[Route("api/[controller]/[action]")]
public void UpdateOperation(Car car)
{
_carRepository.UpdateOperation(car) //UpdateOperation is void with try/catch - throw;
}
To make your calling code work, you don't need to receive anything but the HTTP response message from the server. Even if your method returns void, HTTP servers still send a status code (200, 500, etc.) and some headers for you to inspect.
Try this:
public async Task UpdateCar(Car selectedCar, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/UpdateOperation");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(selectedCar), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(uri, content, ct);
if (response.IsSuccessStatusCode)
{
return;
}
else
{
// handle error
}
}
}

C# - How to I get the HTTP Status Code from a http request

I have the below code, working as expected (given correct URL etc) as a POST request. Seems I have a problem reading the Status Code (I receive a successful 201, and based on that number I need to continue processing). Any idea how to get the status code?
static async Task CreateConsentAsync(Uri HTTPaddress, ConsentHeaders cconsentHeaders, ConsentBody cconsent)
{
HttpClient client = new HttpClient();
try
{
client.BaseAddress = HTTPaddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
client.DefaultRequestHeaders.Add("Connection", "keep-alive");
client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
client.DefaultRequestHeaders.Add("otherHeader", myValue);
//etc. more headers added, as needed...
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);
request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");
Console.WriteLine("\r\n" + "POST Request:\r\n" + client.DefaultRequestHeaders + "\r\nBody:\r\n" + JsonConvert.SerializeObject(cconsent, Formatting.Indented) + "\r\n");
await client.SendAsync(request).ContinueWith
(
responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result + "\r\nBody:\r\n" + responseTask.Result.Content.ReadAsStringAsync().Result);
}
);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
Console.ReadLine();
}
}
There is a Status code in your Result.
responseTask.Result.StatusCode
Or even better
var response = await client.SendAsync(request);
var statusCode = response.StatusCode;
It helps to avoid using ContinueWith if you're already inside an async function because you can use the (much cleaner) await keyword.
If you await the SendAsync call you'll get a HttpResponseMessage object you can get the status code from:
Also, wrap your IDisposable objects in using() blocks (except HttpClient - which should be a static singleton or better yet, use IHttpClientFactory).
Don't use HttpClient.DefaultRequestHeaders for request-specific headers, use HttpRequestMessage.Headers instead.
The Connection: Keep-alive header will be sent by HttpClientHandler automatically for you.
Are you sure you need to send Cache-control: no-cache in the request? If you're using HTTPS then it's almost guaranteed that there won't be any proxy-caches causing any issues - and HttpClient does not use the Windows Internet Cache either.
Don't use Encoding.UTF8 because it adds a leading byte-order-mark. Use a private UTF8Encoding instance instead.
Always use .ConfigureAwait(false) with every await on code that does not run in a thread-sensitive context (such as WinForms and WPF).
private static readonly HttpClient _httpClient = new HttpClient();
private static readonly UTF8Encoding _utf8 = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true );
static async Task CreateConsentAsync( Uri uri, ConsentHeaders cconsentHeaders, ConsentBody cconsent )
{
using( HttpRequestMessage req = new HttpRequestMessage( HttpMethod.Post, uri ) )
{
req.Headers.Accept.Add( new MediaTypeWithQualityHeaderValue("*/*") );
req.Headers.Add("Cache-Control", "no-cache");
req.Headers.Add("otherHeader", myValue);
//etc. more headers added, as needed...
String jsonObject = JsonConvert.SerializeObject( cconsent, Formatting.Indented );
request.Content = new StringContent( jsonObject, _utf8, "application/json");
using( HttpResponseMessage response = await _httpClient.SendAsync( request ).ConfigureAwait(false) )
{
Int32 responseHttpStatusCode = (Int32)response.StatusCode;
Console.WriteLine( "Got response: HTTP status: {0} ({1})", response.StatusCode, responseHttpStatusCode );
}
}
}
You could simply check the StatusCode property of the response:
https://learn.microsoft.com/en-us/previous-versions/visualstudio/hh159080(v=vs.118)?redirectedfrom=MSDN
static async void dotest(string url)
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode.ToString());
}
else
{
// problems handling here
Console.WriteLine(
"Error occurred, the status code is: {0}",
response.StatusCode
);
}
}
}
#AthanasiosKataras is correct for returning the status code itself but if you would also like to return the status code value (ie 200, 404). You can do the following:
var response = await client.SendAsync(request);
int statusCode = (int)response.StatusCode
The above will give you the int 200.
EDIT:
Is there no reason why you cannot do the following?
using (HttpResponseMessage response = await client.SendAsync(request))
{
// code
int code = (int)response.StatusCode;
}

Error on ConfigureAwait(false)

I am trying to retrieve some data from an API, the following is my piece of code that makes the request after authenticating and assigning the completed URL.
public async Task<T> GetAPIData<T>(string url)
{
using (var client = HttpClientSetup())
{
var response = await client.GetAsync(url).ConfigureAwait(false);
var JsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(JsonResponse);
}
}
private HttpClient HttpClientSetup()
{
var client = new HttpClient { BaseAddress = new Uri(apiBaseUrl) };
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = authenticationHeader;
return client;
}
I am getting an error on the line with ConfigureAwait(false);
as
"HTTPResponseMessage does not contain a definition for ConfigureAwait"
. Could anyone help me as to what might be going wrong?

HttpClient.DeleteAsync and Content.ReadAdStringAsync always return null

When I'm using DeleteAsync function in HttpClient (System.Net.Http) and retrieve the content with Content.ReadAsStringAsync() I always get null returned.
I've tried the same with GET, POST and PUT - and they always return some result.
Here is my code:
HttpClient _client = new HttpClient();
_client.BaseAddress = new Uri("http://httpbin.org/");
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = _client.DeleteAsync("/delete").Result;
string res = await response.Content.ReadAsStringAsync();
return await JsonConvert.DeserializeObjectAsync<T>(res);
I always get null returned.
However, all of this works:
GET:
HttpResponseMessage response = _client.GetAsync("/get").Result;
string res = await response.Content.ReadAsStringAsync();
return await JsonConvert.DeserializeObjectAsync<T>(res);
POST:
HttpResponseMessage response = _client.PostAsync("/post", new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json")).Result;
string res = await response.Content.ReadAsStringAsync();
return await JsonConvert.DeserializeObjectAsync<T>(res);
PUT:
HttpResponseMessage response = _client.PutAsync("/put", new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json")).Result;
string res = await response.Content.ReadAsStringAsync();
return await JsonConvert.DeserializeObjectAsync<T>(res);
But DeleteAsync() and ReadAsStringAsync() always return me null.
According to RFC you have to return body when returning status code 200 OK.
Your code never checks the message response for the StatusCode. Unlike WebClient, HttpClient does NOT throw when the StatusCode is not in the 2xx range.
I bet that if you check the HttpResponseMessage.StatusCode/HttpResonseMessage.ReasonPhrase values you will find that the server returned a code other than 200.
For example:
HttpClient _client = new HttpClient();
_client.BaseAddress = new Uri("http://httpbin.org/");
...
var response = await _client.DeleteAsync("/delete");
if (response.IsSuccessStatusCode)
{
var result=await response.Content.ReadAsStringAsync();
....
}
You can also call the EnsureSuccessStatusCode method to throw an exception if the response status is not a success code:
HttpClient _client = new HttpClient();
_client.BaseAddress = new Uri("http://httpbin.org/");
...
var response = await _client.DeleteAsync("/delete");
response.EnsureSuccessStatusCode();
var result=await response.Content.ReadAsStringAsync();
EDIT
By the way, running the following as is on .NET 4.5, returns a body:
var _client = new HttpClient();
_client.BaseAddress = new Uri("http://httpbin.org/");
var response = await _client.DeleteAsync("/delete");
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
Adding the Accept header doesn't make any difference
I have same case... for now I dont know method overload for DeleteAsync which accept content parameters like post. So I switch API from Delete to Post.
Do you know:
base_address + relative_address
"http://www.youdomain.com/myservice/" + "/test" = "/test".
This is why you get nothing

Categories

Resources