await function not executed? - c#

I found this piece of code online on csharpstar.com as I was trying to understand more about async and await. Can someone help me understand why when I debug it I reach the line where await client.GetStringAsync ("http://www.CsharpStar.com"); is assigned to result, and then the debugger doesn't move onto the next line from try, and doesn't enter catch either, it just seems to resume execution from Main?
If the await line throws a timeout error or something should it not go to catch?
Also weird that when control/flow resumes to Main, it doesn't go through line ReadLine(), which it executed earlier (before entering the GetSite method), however the ReadLine() takes effect after exiting the GetSite method.
What is the explanation of await function disrupting the regular flow? Why can't I debug the next line, so I can see the value stored into the result variable?
using System;
using System.Net.Http;
using System.Threading.Tasks;
using static System.Console;
namespace CSharpStar
{
class Program
{
static void Main(string[] args)
{
Task.Factory.StartNew(() => GetSite());
ReadLine(); // **...to here (2)**
}
private async static Task GetSite()
{
HttpClient client = new HttpClient();
try
{
var result = await client.GetStringAsync ("http://www.CsharpStar.com"); // **debugger jumps from here (1)**
WriteLine(result);
}
catch (Exception exception)
{
try
{
//This asynchronous request will be invoked if the first request is failed.
var result = await client.GetStringAsync ("http://www.easywcf.com");
WriteLine(result);
}
catch
{
WriteLine("Entered Catch Block");
}
finally
{
WriteLine("Entered Finally Block");
}
}
}
}
}

Not sure what article you were reading, but you should stop there. Task.Factory.StartNew is not recommended, but Task.Run is.
What is happening is that the control is returned to the caller (Main in this case) as soon as the await keyword is reached. Since you are not awaiting for the Task to finish, the program goes on to the Console.WriteLine line. This is known as a fire and forget call.
If you want to wait for the function to finish, change your code to:
static void Main(string[] args)
{
// change to the recommended Task.Run method
var task = Task.Run(() => GetSite());
task.GetAwaiter().GetResult(); // block until the Task is finished
ReadLine();
}

Related

Trying to call async method - await vs GetAwaiter().GetResult();

I am trying to write a class with a method that will get some data from a REST API (the googleapi for youtube playlists) and dump that data into an ObservableCollection. The problem I am encountering is that when I call this:
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
the code executes.
When I call this:
await this.getPlaylistItemsAsync();
it simply skips over the code.
I am pretty new to the whole asynchrounous programming thingy... I thikn I understand the basic concepts.. I just can't figure out how to do it :(
The full code is here:
#define DEBUG
//#define TestEnvi
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
namespace IntuifaceYTPlaylist {
public class IFYT_Playlist {
public string playlistID {get;set;}= "PLYu7z3I8tdEmpjIoZHybXD4xmXXYrTqlk"; // The ID with which we identify our playlist
private string key = "supersecretAPIkey"; // The API-Key we use to access the google-API
public ObservableCollection<string> videosList {get;set;}= new ObservableCollection<string>();
public IFYT_Playlist () {
Console.WriteLine("Class Loaded!");
#if TestEnvi
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
Console.WriteLine("This worked!");
await this.getPlaylistItemsAsync();
Console.WriteLine("This didn't!"); //In fact this line isn't even executed :(
#endif
}
#region getData
public async void update (){
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
}
// Access the REST-API to retrieve the full dataset
// TODO: Manage connection to the API - DONE
// TODO: Parse JSON
public async Task<ObservableCollection<string>> getPlaylistItemsAsync(){
var output = new ObservableCollection<string>();
string URL = "https://www.googleapis.com/youtube/v3/playlistItems";
HttpClient client = new HttpClient();
string query = URL + "?key=" + this.key + "&part=contentDetails&playlistId=" + this.playlistID + "&maxResults=50";
var response = await client.GetStringAsync(query); //Dump the JSON string into an object!
# if DEBUG
// Dump the response into a file - just so we can check it if something goes wrong...
using (StreamWriter outputFile = new StreamWriter(Path.Combine("", "Dump.json")))
{
outputFile.WriteLine(response);
}
#endif
var responseData = JsonConvert.DeserializeObject<dynamic>(response);
// Iterate over the items in the list to get the VideoIDs of the individual videos
foreach (var item in responseData.items){
output.Add(JsonConvert.SerializeObject(item.contentDetails.videoId));
}
Console.WriteLine(output);
#if DEBUG //Let's see if that worked....
Console.WriteLine();
Console.WriteLine("Printing VideoIDs:");
Console.WriteLine();
foreach (var item in output){
Console.WriteLine(item);
}
Console.WriteLine();
#endif
this.videosList = output;
return output;
}
#endregion
}
}
The program I use to call this looks like this:
using System;
using IntuifaceYTPlaylist;
namespace TestEnvi
{
class Program
{
static void Main(string[] args)
{
Create();
}
static async void Create(){
IFYT_Playlist playlist = new IFYT_Playlist();
playlist.getPlaylistItemsAsync().GetAwaiter().GetResult();
Console.WriteLine("This worked!");
await playlist.getPlaylistItemsAsync();
Console.WriteLine("Did this?");
}
}
}
Invoked method immediately returns to the caller (i.e. to the Main) on first await and from there, both (the caller and the invoked method) run concurrently. Yet, since the Main finishes first, the whole program ends.
Thus, if you want to wait for asynchronous call completion you may change Create() to return Task rather than void and then you can wait such as: Create().Wait();
It's hard to tell from your code example, where exactly you're trying to update the list, because the code which you are pointing out to can't even be compiled. You can't use the await keyword in constructors, because constructors can't be async.
The main reason why you don't see console output is because your Main method doesn't wait for your async void Create to finish, because Create is async operation and as we know it's non blocking. Therefore your main thread just triggers the Create operation and continue doing other stuff below. But there is nothing below and that's it, the program is done.
To fix it, you should either turn your Main method to async method and call await Create(), or just call Create().Wait. You can also call Console.ReadLine if this is the console application.
By the way, it works with this.getPlaylistItemsAsync().GetAwaiter().GetResult();, because it's not asynchronous code any more, your Create method is blocked and it waits for the getPlaylistItemsAsync to finish. Similarly your Main method also waits for the Create to return, so that the program keep working.
You also have async void update method which you probably use somewhere (I don't know), so be careful with it since you don't have a way to know whether the method has finish its operation or not. Below is simplified explanation of asynchronous code in C# and why it might be bad to return void from the async method.
A bit about asynchronousy
The way how we can describe an asynchronous operations is that the operation is not blocking which means that you can tell that you want to begin the operation and continue doing other stuff not waiting the operation to finish its work. But this is not very useful to just start the operation (sometimes it might be useful), you usually want to do something when the operation is completed, failed etc. So in .NET the async operation returns Task or Task<T> which is the abstraction over the operation which might be completed or might be still in progress. Then you can attach your own code to be executed when a task is completed.
What happens under the hood when you await an operation
Keep in mind that this description is too simplified than what is actually happening.
So when you do something like this:
public async Task IFYT_Playlist () {
await this.getPlaylistItemsAsync();
... Do some other stuff when the `getPlaylistItemsAsync` has been completed
}
The IFYT_Playlist method attaches the code which is below await this.getPlaylistItemsAsync(); to the task which is returned by the method and return immediately. Again this is not what's actually happening, but can get you a basic idea:
public async Task IFYT_Playlist () {
Task resTask = this.getPlaylistItemsAsync();
return resTask.ContinueWith(t => ...Do some other stuff when the `getPlaylistItemsAsync` has been completed);
}
So that as it turned out async operation should return Task so that the caller will be able to attach a continuation to it (with ContinueWith) method. Do you see the problem now? If your return type is void, the caller won't be able to attach the code which should be executed when the operation has been completed. So, if getPlaylistItemsAsync's returns type is void, you can't await this.getPlaylistItemsAsync(), because it's impossible to call ContinueWith on nothing (void). Therefore you can't even have await with method that returns void.
public async Task IFYT_Playlist () {
await this.getPlaylistItemsAsync(); // doesn't compile
}
Therefore your update method should return Task or Task<T> for any suitable T in your case rather than nothing (void).

Use of Async and await in console Application

I have four methods.
Main: only calls the preform method
Working: displays "please wait for the user"
Taking Time: A program that takes time to execute.
Preform: Calls the taking time and working methods asynchronously.
The following is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncObservation
{
class Program
{
static void Main(string[] args)
{
preform();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
Thread.Sleep(1000);
Console.WriteLine("The Program finished");
}
public static async void preform()
{
Task timer = Takingtime();
Task wait = Working();
}
}
}
In the end: I need to display
This program started.
Please wait, the program is running
The program ended.
I see several problems in your program.
Although Preform is neither async nor an event handler, it does not return a Task
The tasks started in Preform are not awaited for before you finish Preform. Hence you never know when they are finished, nor what the results are (exception?). You could even end your program before they are finished
After you start a Task it is not guaranteed when it will run. You can only be sure that statements are already executed if you await for the Task.
Using async-await is a method to make sure that your thread looks around to see if it can do useful stuff instead of waiting idly if it has to wait for something. Thread.Sleep is a busy wait. If you want to look around to see if you can do something else use await Task.Delay(TimeSpan.FromSeconds(1)) instead.
In your case, you can't be sure that any Console line has been written until you await the procedure that should write your line. If you start your second Task before awaiting the first, you don't know how far the first task already proceeded, and thus you don't know for sure that the text already has been written to the Console.
C# 7.1 introduced async Task Main(), so you could use that instead of the traditional void Main. It saves you from catching and interpreting the AggregateException that is thrown by the Task you start to make your process async.
If you don't want to use the async Main, you can of course use Task.Run to call an async function:
static void Main(string[] args)
{
try
{
var preformTask = Task.Run( () => Preform() );
DoSomethingElse(); // if needed
preformTask.Wait(); // wait for preformTask to finish
Console.WriteLine("Task completed; press any key to finish");
Console.ReadKey();
}
catch (Exception exc) // inclusive ggregateException if one of your Task fails
{
ProcessException(exc)
}
}
static async Task preform()
{
// To be certain that the Console Line has been written: await
await Takingtime();
// if here, you are certain that the Line has been written,
// or course you have lost parallel processing
await Working();
}
For completeness: the other functions
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
// either return a completed Task, or await for it (there is a difference!
await Task.CompletedTask;
// or:
return Task.CompletedTask; // do not declare async in this case
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
//Use Task.Delay instead of Sleep
await Task.Delay(TimeSpan.FromSeconds(1); // improved readability
Console.WriteLine("The Program finished");
}
Because of the awaits in Preform you are certain that the text has been written. However, you've lost some parallellism.
If you really want those procedures to execute at the same time, you can't be certain about when text will be written. If that is important, then split the Parts that should be run first (write Console) from the parts that should run in parallel (Task.Delay)
static async Task preform()
{
// Do the things that should be done before parallel tasks are run
await DoThisFirst();
// start the Tasks that can work parallel: not sure what statements are executed first
var taskA = DoTaskA();
var taskB = DoTaskB();
// if here, you are free to do something else
// can't be sure about the status of taskA nor taskB
DoSomethingElse();
// if you want to do something after you know that the tasks have completed:
// await the tasks here:
await Task.When (new Task[] {taskA, taskB});
// if here, you are certain that all parallel tasks have completed successfully
// if desired fetch the return values of the Tasks:
var returnValueA = taskA.Result;
var returnValueB = taskB.Result;
// do all async things of which you needed to be certain that both tasks finished
// for example:
await ProcessResults(returnValueA, returnValueB);
}
In a console app it is OK to use a .Wait() call in an void Main method.
In some contexts where there is synchronisation necessary .Wait() can cause deadlocks (ASP.NET has a request to synchronise on or XAML/WinForms which have a UI thread), but there is nothing to synchronise on here.
static void Main()
{
preform.Wait()
}
This will wait for the async work to complete synchronously. You need the method to run synchronously so that it does not return early. If you use async void and await the method will return immediately and exit the method, await does not work in a Main method.
I would also suggest using await Task.Delay(1000); rather than Thread.Sleep(1000); as this is the canonical async way to idle.
For your code example:
class Program
{
static void Main(string[] args)
{
preform().Wait();
Console.ReadLine();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
await Task.Delay(1000);
Console.WriteLine("The Program finished");
}
public static Task preform()
{
return Task.WhenAll(
Takingtime(),
Working());
}
}
Use Stephen Cleary's Nito.AsyncEx library (available via Nuget) to provide an asynchronous context for a console application. See here for more details.
Your application can then be written as ...
class Program
{
static int Main(string[] args)
{
try
{
Console.WriteLine("The application has started");
AsyncContext.Run(() => LongRunningTaskAsync(args));
Console.WriteLine("The application has finished");
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return -1;
}
}
static async Task LongRunningTaskAsync(string[] args)
{
Console.WriteLine("The long running task has started");
// use Task.Delay() rather than Thread.Sleep() to avoid blocking the application
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
Console.WriteLine("The long running task has finished");
}
}
Use preform().Wait() in the constructor. So the call is awaited. Then use await Takingtime() and await Working() in the preform method.
And you have to change the return type to Task.

What causes a Task to complete?

I'm trying to find out how to use WhenAll to let two methods run at once, and once they both finish, collect the results without blocking by using .Result
I have this little console app test:
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
public static void Main(string[] args)
{
var run = TaskRunner();
Debug.WriteLine(run);
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
} else
{
Debug.WriteLine("this failed!");
}
}
public static async Task<string> TaskRunner()
{
var taskOne = OneAsync();
var taskTwo = TwoAsync();
var tasks = await Task.WhenAll(taskOne, taskTwo);
var retval = tasks[0] + tasks[1];
return retval;
}
public static Task<string> OneAsync()
{
return Task.Run(() =>
{
return "test1";
});
}
public static Task<string> TwoAsync()
{
return Task.Run(() =>
{
return "test2";
});
}
}
}
This currently prints this worked! to my Output window... However, if I comment out Debug.WriteLine(run); it prints this failed!... Why does the Task complete simply by being logged to the output window?
I'm trying to understand a huge problem in a complex piece of code and this little test is my MCVE to hopefully shed some light on what is happening behind the scenes.
This happens just by pure chance. The way you are starting your task is with Task.Run. This essentially creates a new thread on which the (synchronous) action is executed. It returns a task for the completion of that thread.
So OneAsync and TwoAsync will each spawn a new thread that then immediately returns a string. This will happen very quickly but there’s still some overhead for creating those threads which means that it won’t be instantaneous.
TaskRunner then calls both those methods (spawning the threads), and then asynchronously waits for both threads to finish. Since the threads are not completely instantly, this TaskRunner method also won’t complete instantly.
Now, in your main, you are starting the asynchronous TaskRunner, which we figured will take “a very short moment”. You do not await the task, so the execution continues immediately. Debug.WriteLine is executed to print something (it probably doesn’t really matter that it’s the task in question that is being printed), and then you are checking the state of the task.
Since printing stuff is relatively slow (compared to other operations), this is probably the reason why the tasks ends up being completed. And when you remove the printing, the if is just reached too quickly for the task to finish.
As you likely noticed, working like that with asynchronous tasks does not appear to be a good idea. That’s why you should always await the task when you depend on its result.
// note the *async* here; async main methods are supported with C# 7.1
public static async void Main(string[] args)
{
var run = TaskRunner();
// await the task
await run;
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
}
else
{
Debug.WriteLine("this failed!");
}
}

TaskCanceledException with ContinueWith

I've been trying to figure out why I'm getting a TaskCanceledException for a bit of async code that has recently started misbehaving. I've reduced my issue down to a small code snippet that has me scratching my head:
static void Main(string[] args)
{
RunTest();
}
private static void RunTest()
{
Task.Delay(1000).ContinueWith(t => Console.WriteLine("{0}", t.Exception), TaskContinuationOptions.OnlyOnFaulted).Wait();
}
As far as I'm aware, this should simply pause for a second and then close. The ContinueWith won't be called (this only applies to my actual use-case). However, instead I'm getting a TaskCanceledException and I've no idea where that is coming from!
You are using the wrong taskcontinuationoption:
See following link : https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcontinuationoptions%28v=vs.110%29.aspx
It says :
Specifies that the continuation task should be scheduled only if its antecedent threw an unhandled exception. This option is not valid for multi-task continuations.
As guys said above this call requires just antecedent-task in faulted-status otherwise will throw TaskCanceledException, for this concrete case you can generalize ContinueWith to process all statuses:
await Task.Delay(1000).ContinueWith(
task =>
{
/* take into account that Canceled-task throw on next row the TaskCancelledException */
if (!task.IsFaulted) {
return;
}
Console.WriteLine("{0}", task.Exception);
// do smth like 'throw task.Exception.InnerException'
});
I also received this error:
The block of code looked like this:
private void CallMediator<TRequest>(TRequest request) where TRequest : IRequest<Unit>
{
_ = Task.Run(async () =>
{
var mediator = _serviceScopeFactory.CreateScope().ServiceProvider.GetService<IMediator>()!;
await mediator.Send(request).ContinueWith(LogException, TaskContinuationOptions.OnlyOnFaulted);
});
}
private void LogException(Task task)
{
if (task.Exception != null)
{
_logger.LogError(task.Exception, "{ErrorMessage}", task.Exception.Message);
}
}
Reading the documentation for the ContinueWith method, it has the following remarks:
The returned Task will not be scheduled for execution until the current task has completed. If the continuation criteria specified through the continuationOptions parameter are not met, the continuation task will be canceled instead of scheduled.
So for me, it called the first task (mediator.Send(request)), then it continued with the task ContinueWith(...), which is the one I awaited. However, since an exception had not occurred in the first task, the second task was cancelled. Therefore, when awaiting the second task, it threw a TaskCanceledException.
What I did, was to change the code to this:
private void CallMediator<TRequest>(TRequest request) where TRequest : IRequest<Unit>
{
_ = Task.Run(async () =>
{
var mediator = _serviceScopeFactory.CreateScope().ServiceProvider.GetService<IMediator>()!;
try
{
_ = await mediator.Send(request);
}
catch (Exception ex)
{
_logger.LogError(ex, "{ErrorMessage}", ex.Message);
}
});
}
Instead of using .ContinueWith(...), I have replaced it with just a regular try-catch block in case of the task I am interested in fails. I think this simplifies the code and makes it more readable.
In the question, there is this line of code:
Task.Delay(1000).ContinueWith(t => Console.WriteLine("{0}", t.Exception), TaskContinuationOptions.OnlyOnFaulted).Wait();
I would rewrite it to:
try
{
Task.Delay(1000).Wait();
}
catch (Exception ex)
{
Console.WriteLine("{0}", ex);
}

Why does Console.In.ReadLineAsync block?

Start a new console app using the following code -
class Program
{
static void Main(string[] args)
{
while (true)
{
Task<string> readLineTask = Console.In.ReadLineAsync();
Debug.WriteLine("hi");
}
}
}
Console.In.ReadLineAsync is blocking and doesn't return until a line is entered in the console.. so "Hi" never gets written to the console.
Using await on Console.In.ReadLineAsync also blocks.
It was my understanding that the new Async CTP methods do not block.
What is the reason for this?
Here is another example
static void Main(string[] args)
{
Task delayTask = Task.Delay(50000);
Debug.WriteLine("hi");
}
This behaves as I expect, it goes straight to the next line and prints "hi" since Task.Delay does not block.
daryal provided the answer here
http://smellegantcode.wordpress.com/2012/08/28/a-boring-discovery/
It seems ReadLineAsync is not actually doing what it's supposed to do. Bug in the framework.
My solution is to use ThreadPool.QueueUserWorkItem in a loop so each call to ReadLineAsync is done on a new thread.
This can now be found in the documentation:
Read operations on the standard input stream execute synchronously. That is, they block until the specified read operation has completed. This is true even if an asynchronous method, such as ReadLineAsync, is called on the TextReader object returned by the In property.
Another solution:
static void Main()
{
using (var s = Console.OpenStandardInput())
using (var sr = new StreamReader(s))
{
Task readLineTask = sr.ReadLineAsync();
Debug.WriteLine("hi");
Console.WriteLine("hello");
readLineTask.Wait();// When not in Main method, you can use await.
// Waiting must happen in the curly brackets of the using directive.
}
Console.WriteLine("Bye Bye");
}

Categories