Console App Terminating Before async Call Completion - c#

I'm currently writing a C# console app that generates a number of URLs that point to different images on a web site and then downloads as byte streams using WebClient.DownloadDataAsync().
My issue is that once the first asynchronous call is made, the console app considers the program to be completed and terminates before the asynchronous call can return. By using a Console.Read() I can force the console to stay open but this doesn't seem like very good design. Furthermore if the user hits enter during the process (while the console is waiting for input) the program will terminate.
Is there a better way to prevent the console from closing while I am waiting for an asynchronous call to return?
Edit: the calls are asynchronous because I am providing a status indicator via the console to the user while the downloads take place.

Yes. Use a ManualResetEvent, and have the async callback call event.Set(). If the Main routine blocks on event.WaitOne(), it won't exit until the async code completes.
The basic pseudo-code would look like:
static ManualResetEvent resetEvent = new ManualResetEvent(false);
static void Main()
{
CallAsyncMethod();
resetEvent.WaitOne(); // Blocks until "set"
}
void DownloadDataCallback()
{
// Do your processing on completion...
resetEvent.Set(); // Allow the program to exit
}

Another option is to just call an async Main method and wait on the task returned.
static void Main(string[] args)
{
MainAsync(args).Wait();
}
static async Task MainAsync(string[] args)
{
// .. code goes here
}
Since .NET 4.5 you can now call GetAwaiter().GetResult()
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
What is the difference between .Wait() vs .GetAwaiter().GetResult()?

If that is all your application is doing, I would suggest leaving out the async call; you specifically want the app to 'hang' until the download is complete, so using an async operation is contrary to what you want here, especially in a console app.

It should be stated that in C# 7.1 Main can now be marked as async.
static async Task Main()
{
await LongRunningOperation();
}

Related

public static Task Run(Func<Task> function);

Can anybody provide any examples/code snippet to use below method.
public static Task Run(Func<Task> function);
I am trying to understand how to use the above overloaded method but I did not find any code in web.
As far as I understand this method takes func delegate as input parameter which should return a Task so please provide me some code snippet.
Thanks,
Vinod
This overload is often used to offload task to a thread pool thread.
Suppose you wrote this method inside console app:
private static async Task DoSomeHeavyInitializationAsync()
{
// some heavy calculations;
// some async I/O (e.q. reading from database, file, etc);
await SomeMethodAsync(...);
// again some heavy calculations, async I/O, etc...
}
Now you want to call it from Program.Main, and keep Main responsive: if user don't want to wait app being initialized, he can press [enter] and terminate the app.
So, you need to offload task to be sure, that its code won't run on main thread. Task Run(Func<Task>) helps you:
static void Main(string[] args)
{
Task.Run(DoSomeHeavyInitializationAsync);
// do something else...
Console.ReadLine();
}

Task and asynchronous in Console program

I have just read about special cases in console projects. Could you tell me whether my approach is right. Two jobs there i am not sure whether i should just use await inside Task.Run as i did here, if it is correct can you explain what would be the diffrence if i would delete both awaits from here. Next question what if i would remove .Wait() from WhenAny. Generally is it correct approach in console apps? Forget about proposing async Main so far, let's talk with void.
public class Program
{
public static void Main()
{
//jobs can work in parael not blocking program
var job0 = Task.Run(async () => await new DoThisAsync().Run());
var job1 = Task.Run(async () => await new DoThatAsync().Run());
//Any Independent synchronous work can run meantime jobs
IndependentSynchronousMethod;
//We wait on tasks
Task.WhenAll(job0, job1).Wait();
}
}
Most of this code was not needed
Also if you make your Main async you can do the following
public static async Task Main()
{
var job0 = DoThisAsync();
var job1 = DoThatAsync();
//Any Independent synchronous work can run meantime jobs
IndependentSynchronousMethod;
//We wait on tasks
await Task.WhenAll(job0, job1)
}
To make your Main async
Project -> Build -> Advanced - Language Version >= 7.1
Additional Resources
Task.WhenAll Method
Creates a task that will complete when all of the supplied tasks have
completed.
Can't specify the 'async' modifier on the 'Main' method of a console app
Update
Arie : to make this clear forget about async Main
With no async signature you could do this in a console app.
Task.WhenAll(job0, job1).Wait();
Your code was just wrong and wouldn't compile. However besides that, you were trying to wrap async calls in a task, which is redundant in this case. You are trying to create a task to run a task and its just not needed.
The async signature returns a task by default, Just pass them to WhenAll
If i just call Task.WhenAll(job0, job1) without Wait at the end
program would end before waiting?
Calling an async method returns a task that has already been started. So there is no actual code necessary to force it to run. However, because the task is started something needs to wait for it some how, or in the example the process will end
Task.WhenAll aggregates the tasks, it doesn't start them for you, however if you don't wait for it, or await it, it its self just lets control flow through to the exit of the application

Does C# Async/Await work like interrupt?

I tested console application like this:
class Program
{
static void Main(string[] args)
{
Test();
Console.WriteLine("C");
Console.ReadLine();
}
static async void Test()
{
Console.WriteLine("A");
await Task.Delay(2000);
Console.WriteLine("B");
}
}
This application printed A and C immmediately then B after 2 seconds. It looks fine. But I read an article about async/await "There Is No Thread" (http://blog.stephencleary.com/2013/11/there-is-no-thread.html), it says async/await does not create additional thread.
So back to my console application, I think that the main thread is blokced on Console.ReadLine(), so the remain code in Test() (Console.WriteLine("B")) is not executed until Console.ReadLine() is complete. But actual result is different, the remain code is executed regardless of the blocking of main thread.
I want to know that await works like CPU interrupt, so the instruction pointer is moved to the remain code(Console.WriteLine("B");) and moved back to interrupted position(Console.ReadLine();) after execution?
Unlike a Windows form app, console applications don't have a single "blessed" thread (the UI thread). As such, no special synchronization context is employed by default in console applications and so the continuations that await makes use of are in fact scheduled using the thread pool.
So there's no need to "interrupt" the thread that's currently waiting on Console.ReadLine - another thread is used instead.

Main Thread terminates before Task thread completion

Hi i need your help guys,
i declared new Task inside my main method like this:
static void Main(string[] args)
{
Task firstTask = Task.Factory.StartNew(()getPackage(packageId));
Task secondTask=firstTask.ContinueWith((_=>UpdatePackage(myPackage)));
}
My problem is, the main thread terminates before my task completes its action.
How should I wait Task to complete its action before terminating the main thread?
Add the following code to make your main thread block until you hit enter in the command window.
Console.Readline();
UPDATE:
If you want a non-interactive solution, then you could just wait for all the tasks to complete.
Task.WaitAll(firstTask, secondTask);
You can use an alternate paradigm for dealing with this.
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
Task firstTask = new Task(()=>getPackage(packageId));
firstTask.ContinueWith(()=>UpdatePackage(myPackage)));
await firstTask.Run();
}
Be careful with mixing asynchronous and synchronous code like this, but, for your purposes, this should work fine (if this were winforms or WPF, you might have to worry about messaging to the UI thread, but that's not relevant here.
Assign your task to a Thread and then in your main call the .Join() function of the created thread (after it has been started of course). That way the application will wait until the task is over before ending.
This solution is more complexe than a Console.ReadLine but allows you to leave when the ask is over not before and not after.

await Task.Run(...) behaving differently for console and windows application

I have a console application with the following code
static void Main(string[] args) {
Method();
Console.ReadKey();
}
private static void Method() {
Task t = DoSomething();
t.Wait();
Console.WriteLine("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
Everything works exactly as I expect it to and the console displays "Finished" one second after running the program. When I move the same code into a windows application then I find that the program just stops
private void button1_Click(object sender, EventArgs e) {
Task t = DoSomething();
t.Wait();
MessageBox.Show("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
The debugger shows the current line of execution is t.Wait(), even after the Task in the DoSomething method has been run.
Is there something different that I need to do in a windows application that I don't need to do in a console application? Or am I fundamentally misunderstanding something?
That's something that happens quite often. You're causing a deadlock.
To put it simply, frameworks like WinForms and WPF "enforce" a thread synchronization context, which means that whenever you launch a new task, the rest of your code will continue on the same thread as it started. This is done to ensure that, for example, code that started on the UI thread will continue running on the same thread after the task returns.
Because you're blocking on the task (with the Wait method), and the task is trying to return a value to that blocking thread, both threads go into a deadlock state.
This behaviour doesn't happen in a console application because no thread synchronization context is enforced, the continuation of a task can run on a completely different third thread.
Stephen Cleary explains this very well here: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Categories

Resources