C# Console App exits abruptly when calling async methods in Debug - c#

It happens on Console and Windows Service apps, haven't tested on Windows Forms or WPF. When stepping thru the code whenever it hits an async call with await, the debug session exits abruptly, can't go further. As a workaround I'm using Task.Run() but changing all the async calls to use Task.Run() syntax during debug, and put it back to "await" syntax for deployment is a hassle.
Here in this method below, the following line is the issue during Debug, it works as expected when deployed.
var response = await httpClient.SendAsync(request);
Work around while debugging is to change the above line to this:
//var response = await httpClient.SendAsync(request);
var task = Task.Run(() => httpClient.SendAsync(request));
task.Wait();
var response = task.Result;
Code:
private static async Task<string> SendRequest()
{
string result = "";
string url = "http://localhost:5119/WeatherForecast";
var URL = new Uri(url);
var method = new HttpMethod("GET");
using (var request = new HttpRequestMessage(method, URL))
{
var response = await httpClient.SendAsync(request);
//var task = Task.Run(() => httpClient.SendAsync(request));
//task.Wait();
//var response = task.Result;
result = await response.Content.ReadAsStringAsync();
}
return result;
}

Related

Async method calling async method and awaiting another method (http client)

I have some problem with async method.
public async void MakePost()
{
var cookieArray = GetCookies().Result;
(...)
}
async public Task<string[]> GetCookies()
{
(...)
var response = await httpClient.SendAsync(request);
string cookieTempSession = response.Headers.ToString();
(...)
return cookieArray;
}
Nothing happening after var response = await httpClient.SendAsync(request); I put breakpoint in next line string cookieTempSession = response.Headers.ToString(); but it never reach it. I tried to "try catch" but also nothing happend. When I merge this two methods into one it works perfect but it's not so pretty. I just wondering what happened there.
Since the first method is async, you should use await instead of Result:
var cookieArray = await GetCookies();
If you are not programming front end, add ConfigureAwait(false) (why?) to the call, like this:
var cookieArray = await GetCookies().ConfigureAwait(false);
...
var response = await httpClient.SendAsync(request).ConfigureAwait(false);

ASP.Net Forms HttpClient PostAsync no response, no error message

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.

Await in async request webapi 2 client

I am trying to understand await an async operation in asp.net MVC web api 2 client (console application). I believe I have done it wrong (due to lack of understanding await and async). It doesn't seem to run async. Here is code to understand the problem
//Main function
static void Main()
{
RunAsync().Wait();
}
//RunAsync
static async Task RunAsync()
{
using (var client = new HttpClient())
{
var apiUrl = ConfigurationManager.AppSettings["apiurl"];
client.BaseAddress = new Uri(apiUrl);
....some code to fetch data
foreach (var updateObject in updatedata)
{
HttpResponse response = await client.PostAsJsonAsync("webapimethod", updateObject);
if (response.IsSuccessStatusCode)
{
JArray content = await response.Content.ReadAsAsync<JArray>();
}
}
}
}
In the above code, foreach loop I am making request in loop as PostAsJsonAsync call and then I use ReadAsAsync to get response back but request always runs sync. not like fired and then when response arrives read the data.
It works fine but I want it to be async and not waiting on each request. How to achieve that or please explain await async in this context? Trying to read blogs and articles but I don't get how it will work.
The syntax you're probably looking for is this:
public async Task<JArray> GetContentAsync(... updateObject)
{
HttpResponse response = await client.PostAsJsonAsync("webapimethod", updateObject);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<JArray>();
}
}
Here your thread from the GetContentAsync() method will be put back on the threadpool while the client.PostAsJsonAsync is happening due to the await keyword.
Then you can create all the tasks in your method which calls it:
var updateData = fetchData();
var tasks = updateData.Select(d => GetContentAsync(d));
var result = (await Task.WhenAll(tasks)).ToList();
The Select will create a task for each of your result.
The await Task.WhenAll will unwrap the Task<JArray> and create a List<JArray>
You have to move foreach out of RunAsync method.
To get RunAsync in a foreach loop to work in async mode, you have to create several tasks and then call Task.WaitAll

.NET HttpClient hangs when using await keyword?

After considering this interesting answer HttpClient.GetAsync(...) never returns..., I still have a situation where my HttpClient is not returning when I use await (sample code below). In addition. I use this helper routine from both asp.net MVC5 Controllers (UI-driven) and the WebApi. What can I do to:
Use await instead of the (dreaded) .Result and still have this function return?
Reuse this same routine from both MVC Controllers and WebApi?
Apparently, I should replace the .Result with .ConfigureAwait(false) but this seems to contradict with the fact that "Task4" in the post cited above works fine with an await httpClient.GetAsync. Or do I need separate routines for Controller and WebApi cases?
public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
{
if (string.IsNullOrEmpty(elasticQuery)) return null;
IEnumerable<TcMarketUserFullV1> res = null;
using (var hclient = new HttpClient())
{
hclient.BaseAddress = new Uri("https://addr.servicex.com");
hclient.DefaultRequestHeaders.Accept.Clear();
hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
CloudConfigurationManager.GetSetting("jwt-bearer-token"));
// Why does this never return when await is used?
HttpResponseMessage response = hclient.GetAsync("api/v2/users?q=" + elasticQuery + "&search_engine=v2").Result;
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
}
else{log.Warn("...");}
}
return res;
}
UPDATE: My call chain, which starts with a Telerik Kendo Mvc.Grid DataBinding call is as follows:
[HttpPost]
public async Task<ActionResult> TopLicenseGrid_Read([DataSourceRequest]DataSourceRequest request)
{
var res = await GetLicenseInfo();
return Json(res.ToDataSourceResult(request)); // Kendo.Mvc.Extensions.DataSourceRequest
}
Then:
private async Task<IEnumerable<CsoPortalLicenseInfoModel>> GetLicenseInfo()
{
...
// Never returns
var qry = #"app_metadata.tc_app_user.country:""DE""";
return await TcSearchMultiUsersAsync(qry);
}
Then, the routine shown in full above but now WITHOUT the .Result:
public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
{
if (string.IsNullOrEmpty(elasticQuery)) return null;
IEnumerable<TcMarketUserFullV1> res = null;
using (var hclient = new HttpClient())
{
hclient.BaseAddress = new Uri("https://addr.servicex.com");
hclient.DefaultRequestHeaders.Accept.Clear();
hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
CloudConfigurationManager.GetSetting("jwt-bearer-token"));
// This now returns fine
HttpResponseMessage response = hclient.GetAsync("api/v2/users?search_engine=v2&q=" + elasticQuery");
if (response.IsSuccessStatusCode)
{
// This returns my results fine too
var content = await response.Content.ReadAsStringAsync();
// The following line never returns results. When debugging, everything flows perfectly until I reach the following line, which never
// returns and the debugger returns me immediately to the top level HttpPost with a result of null.
res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
}
else{log.Warn("...");}
}
return res;
}
You need to await everything. It's not enough that you await on one of them, you need to await on all of them:
This:
HttpResponseMessage response = hclient.GetAsync(
"api/v2/users?q=" + elasticQuery + "&search_engine=v2").Result;
Should be:
HttpResponseMessage response = await hclient.GetAsync(
"api/v2/users?q=" + elasticQuery + "&search_engine=v2");
It is enough to have one blocking call to .Result in order to deadlock. You need "async all the way".

Use HttpClient to send two POST requests 2 seconds apart

I'm trying to write an integration test for a DelegatingHandler that prevents duplicate requests. The handler checks a database to see if the request is already being processed and returns a 407-Conflict if a duplicate request is made while the previous request is still running.
I have the following code in my test:
HttpClient client = new HttpClient();
var responseTask1 = client.PostAsJsonAsync(RequestUriWithDuplicatePrevention, ReadRequestContent("DuplicateRequestJsonContent.json"));
var responseTask2 = client.PostAsJsonAsync(RequestUriWithDuplicatePrevention, ReadRequestContent("DuplicateRequestJsonContent.json"));
var response1 = responseTask1.Result;
var response2 = responseTask2.Result;
Both requests are being logged into the database at the exact same time. How can I delay the second request for a period of time?
I've tried adding a Thread.Sleep(500) but it didn't seem to make a difference.
Revised Code
This code seems to work most of the time but it not 100% reliable.
[TestMethod]
public void ShouldReturn407ConflictWhenDuplicateRequestSubmitted()
{
var results = ExecutePostRequests().Result;
Assert.AreEqual(HttpStatusCode.OK, results[0].StatusCode);
Assert.AreEqual(HttpStatusCode.Conflict, results[1].StatusCode);
}
private async Task<HttpResponseMessage[]> ExecutePostRequests()
{
HttpClient client = new HttpClient();
var task1 = ExecutePost(client, 0);
var task2 = ExecutePost(client, 4000);
var response1 = await task1;
var response2 = await task2;
return new[] {response1, response2};
}
private async Task<HttpResponseMessage> ExecutePost(HttpClient client, int delay)
{
await Task.Delay(delay);
return await client.PostAsync(RequestUriWithDuplicatePrevention,
ReadRequestContent("DuplicateRequestJsonContent.json"));
}
The web service being executed has a Thread.Sleep(5000).
The specific problem in your original code is that it is sleeping between getting results, when you should be sleeping between starting the asynchronous operations.
It could be corrected like so:
var responseTask1 = client.PostAsJsonAsync(...);
Thread.Sleep(2000);
var responseTask2 = client.PostAsJsonAsync(...);
var response1 = responseTask1.Result;
var response2 = responseTask2.Result;
Your revised code does not suffer this issue and should work. Though, I would change this:
var response1 = await task1;
var response2 = await task2;
return new[] {response1, response2};
To a more efficient:
return await Task.WhenAll(task1, task2);

Categories

Resources