When i call async method using httpclient without await cause i don't want to wait response
then throw exception "object reference not set to an instance of an object"
\\ Call PostAsync
var ignore = webRequest.PostAsync(json, token);
\\ PostAsync method
using (var httpClient = new HttpClient())
{
if (!string.IsNullOrEmpty(auth))
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", auth);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// this line throw exception
var response = await httpClient.PostAsync(this.URL, content);
if (response.IsSuccessStatusCode)
{
result = await response.Content.ReadAsStringAsync();
}
}
and then i get error on my visual studio image below.
image
if i don't want to wait response, how i do it?
I think the problem is the basic concept of async await, check this link for a clearer idea:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
Related
I am getting this error when I call add "await" keyword and getting output when I remove "await" keyword
Code:
public class ApiHelper : IApiHelper
{
private const int APiRetryCount = 4;
private static HttpClient client = new HttpClient();
public async Task<string> PostAsync<T>(T payload, string apiEndpoint)
{
for (int i = 0; i < APiRetryCount; i++)
{
client.DefaultRequestHeaders.Accept.Clear();
client.BaseAddress = new Uri("http://app-et-csswrapperapi-dev.azurewebsites.net/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + token.AccessToken);
var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
var response = **await** client.PostAsync(apiEndpoint, content);
}
// if we got here, we have maxed out retry count and got transient failures or are not authorized
// log warning
return default(string);
}
}
I am getting exception:
Sys.WebForms.PageRequestManagerTimeoutException: Sys.WebForms.PageRequestManagerTimeoutException: The server request timed out
But when I replace the line
var response = **await** client.PostAsync(apiEndpoint, content);
with below code, its working fine:
var response = client.PostAsync(apiEndpoint, content).Result;
My doubt is what its making a big difference between await and .Result() ??
There is nothing wrong with your code. This is the way to go var response = await client.PostAsync(apiEndpoint, content);. I suspect you are running into a deadlock in the code outside the method PostAsync. Make sure you use await when you call it: await PostAsync<SomeClass>(instance,"/api/endpoint"); and that you use async/await all the way up to the controller.
Edit: you can check this answer too: https://stackoverflow.com/a/15022170/1817574
I am working on this helper method that will call an API using the body section. I am passing in the url and data in the model. Then I SerializeObject the model, but I am not sure what to return I get the error message about the response.Content is not found.
public static async System.Threading.Tasks.Task<HttpResponse> HttpClientHandlerAsync(string url, object model)
{
var fullUrl = apiUrl + url;
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json");
Client.DefaultRequestHeaders.Add("Accept", "*/*");
Client.DefaultRequestHeaders.Authorization
= new AuthenticationHeaderValue("Bearer", "token");
var response = await Client.PostAsync(fullUrl, data);
return response;
}
Add await in front of your
await Client.PostAsync(fullUrl, data);
Because you're trying to get content of Task
I am not sure what to return I get the error message about the response.Content is not found.
Set a breakpoint and hover over the response to see the status code. You could have a 500 server error, authentication error etc.
Furthermore
using (var client = new HttpClient())
Do not do this. It doesn't work the way you think it does, it will starve your connection pool and eventually throw an exception. You need to define the HttpClient somewhere and continue to reuse the same instance.
Further reading if you care https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
I am having a problem getting the response from the HttpClient PostAsJsonAsync method. I am passing a StringContent data to a POST request but it returns a Forbidden (403) status code.
When I tried adding a default request header (commented line of code), the error changed and it returned a timeout issue:
{System.Net.Http.WinHttpException (0x80072EE2): The operation timed out
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.Tasks.RendezvousAwaitable`1.GetResult()
at System.Net.Http.WinHttpHandler.d__105.MoveNext()}
var content = new StringContent(JsonConvert.SerializeObject(contentBody), Encoding.UTF8, "application/json");
var client = new HttpClient();
client.BaseAddress = new Uri("https://www.example.com");
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var httpResponse = await client.PostAsJsonAsync("api/details", content))
{
if (httpResponse.Content != null)
{
var responseContent = await httpResponse.Content.ReadAsStringAsync();
}
}
When I tried it in Postman, it returned the JSON data. Why doesn't it work in the code? Is there something that blocks my connection?
The BaseAddress property needs to be suffixed with a forward slash:
client.BaseAddress = new Uri("https://www.example.com/");
I have a .NET WebAPI application and this is one of my api:
public IHttpActionResult Get()
{
...building myResult here...
var content = ElasticSearch.Json.ToJson(myResult);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(content, Encoding.UTF8, "application/json");
return ResponseMessage(response);
}
I get a CA2000 error from code analisys:
Error CA2000 In method 'GroupsController.Get(string, string, string,
bool, string)', call System.IDisposable.Dispose on object 'response'
before all references to it are out of
scope
So I modified the code like this:
var content = ElasticSearch.Json.ToJson(myResult);
using (var response = Request.CreateResponse(HttpStatusCode.OK))
{
response.Content = new StringContent(content, Encoding.UTF8, "application/json");
return ResponseMessage(response);
}
So far so good. No memory leaks and the code analyzer is happy again.
Unfortunately now one of my test is complaining that it cannot access anymore a disposed object. Here the test testing that api (just the final part):
// Assert
var httpResponseMessage = await result.ExecuteAsync(CancellationToken.None);
var resultJson = await httpResponseMessage.Content.ReadAsStringAsync();
Assert.AreEqual(expectedJson, resultJson);
The Assert() is complaining that it cannot access an already disposed object, that is the actual api result:
System.ObjectDisposedException : Cannot access a disposed object.
Object name: 'System.Net.Http.StringContent'. at
System.Net.Http.HttpContent.CheckDisposed() at
System.Net.Http.HttpContent.ReadAsStringAsync()
How can I fix that? Disposing the object seems reasonable but at the same time the test should be able to access it
You can use ApiController.OK
return Ok(myResult);
You should not use using (var response = Request.CreateResponse(HttpStatusCode.OK)) because ResponseMessageResult will hold reference to disposed HttpResponseMessage. That's the reason you get this error in assert.
To check, change your code to snippet below and add breakpoint on result. Check result.Response.disposed
using (var response = Request.CreateResponse(HttpStatusCode.OK))
{
response.Content = new StringContent(content, Encoding.UTF8, "application/json");
result = ResponseMessage(response);
}
// result.Response.disposed is true hence error in assert.
return result;
I have this code:
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{"site_id","001"},
{"apikey","abc01201az1024"},
{"trans_id","45364136"},
};
// Get the parameters in the url encoded format
var content = new FormUrlEncodedContent(values);
//Send request
var response = await client.PostAsync(url, content);
DataRoot<Transaction> outPut = null;
if (response.IsSuccessStatusCode)
{
//Get Response
var result = await response.Content.ReadAsStringAsync();
JsonConvert.DeserializeObject<DataRoot<Transaction>>(result);
}
return outPut;
}
In the debug mode at this stage, the code does not produce any response, no error code but stops running:
//Send request
var response = await client.PostAsync(url, content);
there could be a better way but this solved my problem. Call your method from another one using wait:-
public static async Task<string> AuthenticateUser()
{
var t = Task.Run(() => ClassObject.AuthenticateUser("me"));
t.Wait();
Console.WriteLine(t.Result);
Console.ReadLine();
return "ok";
}
Using await like this, can end up in a deadlock.
You can use ConfigureAwait(false) in async methods for preventing such a deadlock.
Update code to:
var response = await client.PostAsync(url, content).ConfigureAwait(false);
This will solve the issue.
Are you sure that it isn't actually returning the response and continuing execution? Because the client.PostAsync() call is awaited execution may continue on a different thread. Therefore, if you're just debugging line by line (via F10 or similar) it may appear that the method never returns; in actuality the entire method has finished execution and your program is running.
You may need to add another breakpoint in the method (after the PostAsync method call). When the PostAsync method returns on a different thread, your debugger should hit the next breakpoint.