This question already has answers here:
async/await - when to return a Task vs void?
(6 answers)
Closed 11 months ago.
I am trying to use this in a method call to get a string from a source
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
string responseBody = await response.Content.ReadAsStringAsync();
Console.Write(responseBody);
When used outside of a method and class, it works fine with my url, and returns the proper string I am looking for. However, when I put it in my class and method, it no longer does anything. No errors, just returns nothing.
For reference, the method I am using looks like this
public async void get(String test) {
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(test);
string responseBody = await response.Content.ReadAsStringAsync();
Console.Write(responseBody);
}
I am clueless why this stops working once I put it into a method.
Make your Method returning a Task and it works
public async Task get(String test)
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(test);
string responseBody = await response.Content.ReadAsStringAsync();
Debug.Write(responseBody);
}
private async void btnTest_Click(object sender, EventArgs e)
{
try
{
Task t = get("https://stackoverflow.com/questions/71787949/c-sharp-httpclient-get-does-not-work-when-put-in-async-method");
IEnumerable<Task> tasks = new[] { t };
await Task.WhenAll(tasks);
}
catch (Exception oException)
{
Debug.WriteLine(oException.ToString());
}
}
Related
I have below code which use httpclient and use sendasync, when I test, it always run twice on API.
Controller :
[HttpGet("GetAllStores")]
public async Task<bookstores> GetAllStores()
{
Console.writeline("Trigger Stores")
return await dbContext.set<bookstores>().toListAsync()
}
httpclient
public async Task<IEnumerable<bookstores>> FetchAllStores()
{
var requestContent = new HttpRequestMessage
{
Method = HttpMethod.Get
};
var response = await httpClient.SendAsync("http://127.0.0.1:5000/GetAllStores", HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
return JsonSerializer.Deserialize<bookstores>(await response.Content.ReadAsStringAsync(), defaultJsonSerializerOptions);
}
Test
public async Task GetSettingProfile_AsExpected()
{
var sut = new ApiClient(
new HttpClient() { BaseAddress=new Uri("http://localhost:40331") });
await sut.FetchAllStores();
}
The output in console is show Trigger Stores two times
Can I know how to make it which call API in one time ?
I have this code:
public async Task<List<Template>> GetTemplates(User user)
{
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("un", user.Username));
postData.Add(new KeyValuePair<string, string>("pw", user.Password));
var content = new FormUrlEncodedContent(postData);
var weburl = "myapp.org/get_templates.php";
var response = await PostResponseTemplates<Template>(weburl, content);
return response;
}
public async Task<List<Template>> PostResponseTemplates<List>(string weburl, FormUrlEncodedContent content)
{
var response = await client.PostAsync(weburl, content);
var json = response.Content.ReadAsStringAsync().Result;
.......
}
But the webcall never returns the result after this line: var response = await client.PostAsync(weburl, content);.
What am I doing wrong?
UPDATE
Here is the void where I call the function right now:
public MemeTemplateList()
{
InitializeComponent();
LoadTemplateList();
}
private void LoadTemplateList()
{
var templateList = App.RestService.GetTemplates(App.User);
....
How to create this async and run it in the page constructor?
Mixing async-await and blocking calls like .Result
public async Task<List<Template>> PostResponseTemplates<List>(string weburl, FormUrlEncodedContent content) {
var response = await client.PostAsync(weburl, content);
var json = response.Content.ReadAsStringAsync().Result; //<--THIS WILL DEADLOCK
//...omitted for brevity
can cause deadlock. Which is why the function does not return.
Remove .Result and make the code async all the way though
public async Task<List<Template>> PostResponseTemplates<List>(string weburl, FormUrlEncodedContent content) {
var response = await client.PostAsync(weburl, content);
var json = await response.Content.ReadAsStringAsync(); //<--THIS
//...omitted for brevity
I would also suggest changing the function definition from being generic
public async Task<List<Template>> PostResponseTemplates(string weburl, FormUrlEncodedContent content) {
//...
}
Since the type is already known within the function
List<Template> response = await PostResponseTemplates(weburl, content);
Finally make sure everything is async all the way up the call stack
public MemeTemplateList() {
InitializeComponent();
//Subscribe to event
loadingTemplates += onLoadingTemplates;
//raise the event to load the templates.
LoadTemplateList();
}
private event EventHandler loadingTemplates = delegate { };
//ASYNC VOID ONLY ALLOWED ON EVENT HANDLER!!!!!!!
private async void onLoadingTemplates(object sender, EventArgs args) {
List<Template> templateList = await App.RestService.GetTemplates(App.User);
//....
}
private void LoadTemplateList() {
loadingTemplates(this, EventArgs.Empty);
}
Reference Async/Await - Best Practices in Asynchronous Programming
I have a web service which calls an external web service. The external service responds after 3-4 seconds.
Right now all the calls are synchronous, but does it make sense to use async calls instead (sample below)?
Will it help with performance (not keeping threads blocked)? Isn't the thread blocked on the first line of GetData()?
Thank you.
public class MyService : WebService
{
[WebMethod]
public string GetData()
{
string response = ExecuteRequest(externalUrl, someContent).Result;
return response;
}
private async Task<string> ExecuteRequest(string url, string content)
{
var httpResponse = await new HttpClient().PostAsync(url, new StringContent(content));
string responseStr = await httpResponse.Content.ReadAsStringAsync();
return responseStr;
}
}
To answer your question: Yes, it does make sense to use async calls instead, but your example is not async. If you wanted to make it async you'd have to do something like this:
public class MyService : WebService
{
[WebMethod]
public async Task<string> GetData()
{
string response = await ExecuteRequest(externalUrl, someContent);
return response;
}
private async Task<string> ExecuteRequest(string url, string content)
{
var httpResponse = await new HttpClient().PostAsync(url, new StringContent(content));
string responseStr = await httpResponse.Content.ReadAsStringAsync();
return responseStr;
}
}
Are the following two methods, getData1Async() and getData2Async() are essentially the same? If so why don't I need EnsureSuccessStatusCode() in getData2Async() method?
class Program
{
static void Main(string[] args)
{
try
{
string uri = "https://www.blahblah.com/getdata";
Task<string> x = getData1Async(uri);
System.Diagnostics.Debug.WriteLine(x.Result);
Task<string> y = getData2Async(uri);
System.Diagnostics.Debug.WriteLine(y.Result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static async Task<string> getData1Async(string uri)
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
static async Task<string> getData2Async(string uri)
{
var httpClient = new HttpClient();
return await httpClient.GetStringAsync(uri);
}
}
getData1Async - here you are getting the object of type HttpResponseMessage and if you don't ensure that response has completed successfully and call response.Content.Read..., the answer will be indeterministic.
getData2Async - directly calls httpClient itself to get the string which internally makes sure that it only returns when data has been received.
My problem is the following:
On the UI thread I have a button event, from where I call a service method:
private async void RefreshObjectsButton_Click(object sender, EventArgs e)
{
var objectService = new ObjectService();
var objects = await objectService.GetObjects(UserInfo.Token);
}
The service method is:
public class ObjectService : ServiceClientBase, IObjectService
{
public async Task<ObservableCollection<ObjectViewModel>> GetObjects(string token)
{
var response = await GetAsync<ObservableCollection<HookViewModel>>("uri_address", token);
return response;
}
}
And the GetAsync method which is implemented in ServiceClientBase:
public async Task<T> GetAsync<T>(string uri, string token)
{
using (var client = CreateClient())
{
try
{
HttpResponseMessage response = new HttpResponseMessage();
response = await client.GetAsync(uri);
T retVal = default(T);
if (response.IsSuccessStatusCode)
{
retVal = await response.Content.ReadAsAsync<T>();
}
return retVal;
}
catch (Exception ex)
{
//TO DO log exception
return default(T);
}
}
}
When execution reaches GetAsync<T>(), the request is sent, I get a result and retVal contains a list of values. However after GetAsync<T>() execution ends, GetObjects() will not continue its execution anymore. I believe it's a deadlock as explained here. However using the advices seen in the previous link didn't resolve my issue. It's clearly I'm missing something here.
Can someone explain why is this deadlock happening, and maybe provide some further advice in resolving this issue?