Xamarin.Forms GetAsync stops debugging without error - c#

My MainPage code-behind:
private void Button_Clicked(object sender, EventArgs e)
{
Query().Wait();
App.Current.MainPage = new Categories();
}
public async Task Query()
{
restaurantsClient = (App.Current as App).restaurantsClient;
try
{
var restaurantsNames = await restaurantsClient.GetCatalogsAsync(1);
}
catch (Exception ex)
{
var x = 0;
}
}
I tried this code too but didn't work, happens the same problem:
async static Task GetRequest(String URL)
{
using (HttpClient client = new HttpClient())
{
// As soon as I try to step over (or even into) this next line, it crashes.
using (HttpResponseMessage response = await client.GetAsync(URL))
{
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
Console.WriteLine(data);
}
}
}
}
Rest-API in C#:
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
When the project reach this line it just die without showing any error.
If I do it in the browser it works.
The API is running locally in my PC (Im using Conveyor to expose the API).
Ok I make a video to see better what Im talking about:
https://youtu.be/ONKTipPsEXI
As you can see after I click Next Step in response line stop executing the rest of the code.

That's because you're using .Wait() of a Task on the UI thread (Button.Clicked event is handled on the UI thread) causing a deadlock. The task is waiting for the UI thread to give it control and the UI thread is waiting for the task to complete. The solution to this is to add async modifier to your event handler and use await Query() instead of Query().Wait().
private async void Button_Clicked(object sender, EventArgs e)
{
await Query();
App.Current.MainPage = new Categories();
}
I'd also recommend reading this article by Stephen Cleary about this matter. Moreover, he's made a fabulous series (A Tour of Task) about C# tasks in general.
UPDATE:
After OP's question update and discussion in this answer's comments; he thinks that there's a problem because he can reach the end of GetCatalogsAsync(int) before the end of GetCatalogsAsync(int, CancellationToken). That's completely natural and is to be expected. Solution:
public async System.Threading.Tasks.Task<CatalogsInCategory> GetCatalogsAsync(int id)
{
return await GetCatalogsAsync(id, System.Threading.CancellationToken.None);
}

Related

What is causing the deadlock?

I know this is not using the proper form, but can someone tell me why the first code snippet works and the 2nd causes a deadlock?
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = DownloadStringV3("https://www.google.com");
}
public string DownloadStringV3(String url)
{
var resp = new HttpClient().GetAsync(url).Result;
return resp.Content.ReadAsStringAsync().Result;
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = DownloadStringV3("https://www.google.com").Result;
}
public async Task<string> DownloadStringV3(String url)
{
var resp = await new HttpClient().GetAsync(url);
return await resp.Content.ReadAsStringAsync();
}
Different synchronization contexts? This is using .NET 4.8
Every time you await something, you say, I am temporary done here, give some other thread a chance to execute and then continue from here, when the async task is completed.
So in your case await new HttpClient().GetAsync(url) switches the the ui thread and waiting for DownloadStringV3("https://www.google.com").Result be done, which will never be the case, because we do never execute return await resp.Content.ReadAsStringAsync().
Thats why you should do async all the way to the root and never call Result.
The first code works, because you block on the UI thread and don't try to switch to another thread, while waiting for it.
To make the second one working you need to:
private async void button1_Click(object sender, EventArgs e)
{
// make with try catch sure, you catch any error, async void is special. Better is async Task
textBox1.Text = await DownloadStringV3("https://www.google.com");
}
public async Task<string> DownloadStringV3(String url)
{
var resp = await new HttpClient().GetAsync(url);
return await resp.Content.ReadAsStringAsync();
}

Xamarin Forms - Wait for async method to complete before continuing

In my Xamarin.Forms application, I have code that opens a popup page (using the Rg Popups plugin) which executes a call to my API that inserts some data on the database.
I need the async call for the popup to open to wait until the popup page's task finishes then execute another async call which updates a ListView in the current view.
However, the popup's async task does not wait until the popup has finished working to continue to the next task, which means the view isn't updated
Here's the code in question:
bool jobTask = await CloseCurOpenJob();
if (jobTask == true)
{
await FillDocuments();
}
await Navigation.PushPopupAsync(new JobClosePopupPage(Base.activeJobId));
return true;
private async Task<string> FillDocuments()
{
HttpClient client = new HttpClient();
try
{
if (jobid > 0)
{
var response = await client.GetStringAsync(myApiUri);
var DocumentsList = JsonConvert.DeserializeObject<List<DocumentHeader>>(response);
Documents = new ObservableCollection<DocumentHeader>((IEnumerable<DocumentHeader>)DocumentsList);
DocumentCount = Documents.Count();
DocumentSubtotal = Documents.Sum(instance => instance.TotalQuantity);
}
return "OK";
}
catch (Exception e)
{
return e.Message;
}
}
And here's the code in the popup page's ViewModel
private async Task<bool> CloseJob(int jobid)
{
HttpClient client = new HttpClient();
try
{
var response = await client.PostAsync(myAPIUri);
string responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
await CheckGetOpenJob();
return true;
}
else
{
await Application.Current.MainPage.DisplayAlert(Base.applicationTitle, responseString, "OK");
return false;
}
}
catch (Exception e)
{
await Application.Current.MainPage.DisplayAlert(Base.applicationTitle, e.Message, "OK");
return false;
}
finally
{
await Navigation.PopPopupAsync();
}
}
I have tried using Task.Run and Task.Delay but the result is still the same - the FillDocuments method runs after the popup has been shown, not after it has been dismissed.
The Task.Wait() and Task.Result will make the program wait for the async task method competed.
If the CloseCurOpenJob() is like public async Task<bool> CloseCurOpenJob(){} You can try the following code:
// Both are applicable to simple Tasks:
bool jobTask = CloseCurOpenJob().Result;
or
Task<bool> result = CloseCurOpenJob();
result.Wait();
bool jobTask = result.Result;
According to your description, you want update the popup when it show. But you sayed that the popup will not show when you used the .Wait() method.
Generally speaking, it shouldn't happen. But you can try to use the Thread.Sleep() such as:
bool jobTask = await CloseCurOpenJob();
Thread.Sleep(1000); //make the thread to wait for 1s and the async task usually completes in 1s
if (jobTask == true)
{
await FillDocuments();
}
But this way seems not elegant, you can post the code about the CloseCurOpenJob() method. In addition, if the CloseCurOpenJob() is public async bool CloseCurOpenJob(), you can make the thread wait without the await. Such as
bool jobTask = CloseCurOpenJob();
I wanted to share something I've figured out:
The problem was not in the code, but the flow of it.
Namely, I needed one page to dismiss a popup while ANOTHER page was working.
The solution I think I found - it has not been tested - is as follows:
Show the popup
Do the processing in the main page's thread after showing the popup - as it's asynchronous, the code will continue to the task.
Dismiss the popup in the main page's code (using the PopAllPopup method of the Rg plugin).
So...
bool jobTask = await CloseCurOpenJob();
if (jobTask == true)
{
await FillDocuments();
}
Would become
await Navigation.PushPopupAsync(new JobClosePopupPage(Base.activeJobId));
bool jobTask = MethodThatProcessesTheData().Result;
await Navigation.PopAllPopupAsync();
I think this is how it's supposed to go...

How to prevent the application from freezing, while checking a lot of PDF files?

I try to create a program checking in a lot of PDF. It can be done from a network drive and take few minutes. The application freeze all during the process and I want to avoid that.
I searched in a lot of posts and videos but I failed to implement it in my program. I tried this code to understand how it works but it failed too...
async private void button1_Click(object sender, EventArgs e)
{
rtbx.AppendText($"Processing...\n");
// This webswite takes 1-2s to be loaded
await HeavyWork(#"https://aion.plaync.com/");
rtbx.AppendText($"End.\n");
}
public Task HeavyWork(string url)
{
List<string> lesinfos = new List<string>();
while (checkBox1.Checked == false)
{
using (WebClient web1 = new WebClient())
{
lesinfos.Add(web1.DownloadString(url));
}
rtbx.AppendText($"{lesinfos.Count}\n");
this.Refresh();
}
rtbx.AppendText($"Done !\n");
return Task.CompletedTask;
}
When I click the button, I am never able to click in the checkbox, and the UI never respond.
Taking into account that you are forced to use a synchronous API, you can keep the UI responsive by offloading the blocking call to a ThreadPool thread. The tool to use for this purpose is the Task.Run method. This method is specifically designed for offloading work to the ThreadPool. Here is how you can use it:
public async Task HeavyWork(string url)
{
List<string> lesinfos = new List<string>();
using (WebClient web1 = new WebClient())
{
while (checkBox1.Checked == false)
{
string result = await Task.Run(() => web1.DownloadString(url));
lesinfos.Add(result);
}
rtbx.AppendText($"{lesinfos.Count}\n");
this.Refresh();
}
rtbx.AppendText($"Done !\n");
}
Notice the async keyword in the signature of the HeavyWork method. Notice the await before the Task.Run call. Notice the absence of the return Task.CompletedTask line at the end.
If you are unfamiliar with the async/await technology, here is a tutorial to get you started: Asynchronous programming with async and await.
Try using DownloadStringTaskAsync(...) with an `await (see example below).
public async Task HeavyWork(string url)
{
List<string> lesinfos = new List<string>();
while (checkBox1.Checked == false)
{
using (WebClient web1 = new WebClient())
{
var content = await web1.DownloadStringTaskAsync(url);
lesinfos.Add(content);
}
rtbx.AppendText($"{lesinfos.Count}\n");
this.Refresh();
}
rtbx.AppendText($"Done !\n");
}
note: WebClient is considered obsolete and it's now recommended to use HttpClient.

client.GetStreamAsync(url) is freezing my UI

So I'm listening to an Server side event with my code to just write it on the console (for now) but it seems that this is making my window's form UI freeze
The code in question (which I'm calling from the main form's function)
static async Task hello()
{
HttpClient client = new HttpClient();
//client.Timeout = TimeSpan.FromSeconds(5);
while (true)
{
try
{
Console.WriteLine("Establishing connection");
using (var streamReader = new StreamReader(await client.GetStreamAsync(url)))
{
while (!streamReader.EndOfStream)
{
var message = await streamReader.ReadLineAsync();
Console.WriteLine(message.ToString());
}
}
}
catch (Exception ex)
{
//Here you can check for
//specific types of errors before continuing
//Since this is a simple example, i'm always going to retry
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine("Retrying in 5 seconds");
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
}
Thanks in advance
I've solved the problem, it appears that async/await task freezes the GUI. To stop this from happening you need to use Task.Run(() => your_function()); when you call an async function
This question might be a possible duplicate of: GUI freezes when using async/await ... so go there if you want to find a bit more knowledge about the subject

Call HttpClient.GetAsync in console application - Deadlock

I searched and saw many posts and I don't know why this simple console call using httpclient.getasync and awaiting it causes it not to complete. here is the code:
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
GetAPI().Wait();
Console.WriteLine("Hello");
//Console.ReadLine();
}
public static async Task GetAPI()
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync("https://www.google.com/");
//var response = client.GetAsync("https://www.google.com/").Result
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
}
If I change to use client.GetAsync("https://www.google.com/").Result; and remove "await" (see commented out code) it will work however I believe that is a no no because I am making an asynchronous function into synchronous. I've seen other posts and blogs about this and it all claims what I am trying to do is correct but when running the example app it just doesn't turn out that way.
You can call wait() in Main.
But be carefull, this only works in console applications and will dead lock in UI applications like WPF, WinForms or in ASP.NET context...
public static void Main(string[] args)
{
try
{
var t = GetAPI();
t.Wait();
Console.WriteLine(t.Result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static async Task<string> GetAPI()
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync("https://www.google.com/");
string content = await response.Content.ReadAsStringAsync();
return content;
}
}
MSDN
This code will work just fine in a console application but will
deadlock when called from a GUI or ASP.NET context.
The issue is that awaiting the client.GetAsync, after getting the result is waiting for main thread to be free and main thread is waiting for client.GetAsync to complete.
var response = await client.GetAsync("https://www.google.com/").ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
Will tell that client.GetAsync to complete on other thread and then return the result back to main thread so that no more dead lock.

Categories