566

I am new to asynchronous programming with the async modifier. I am trying to figure out how to make sure that my Main method of a console application actually runs asynchronously.

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = bs.GetList();
    }
}

public class Bootstrapper {

    public async Task<List<TvChannel>> GetList()
    {
        GetPrograms pro = new GetPrograms();

        return await pro.DownloadTvChannels();
    }
}

I know this is not running asynchronously from "the top." Since it is not possible to specify the async modifier on the Main method, how can I run code within main asynchronously?

Liam
  • 27,717
  • 28
  • 128
  • 190
danielovich
  • 9,217
  • 7
  • 26
  • 28
  • 41
    This is no longer the case in C#7.1. Main methods can be async – Vasily Sliounaiev Sep 27 '17 at 18:17
  • 4
    Here's the [C#7.1 blog post announcement](https://blogs.msdn.microsoft.com/dotnet/2017/10/31/welcome-to-c-7-1/#gist82557368). See the section titled **Async Main**. – styfle Nov 03 '17 at 17:30

19 Answers19

536

As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP.

Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this:

class Program
{
    static async Task Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption.


I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post:

If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable.

Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context).

Here's why this is a problem in Console programs with an async Main:

Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits.

One solution is to provide your own context - a "main loop" for your console program that is async-compatible.

If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My Documents\Microsoft Visual Studio Async CTP\Samples(C# Testing) Unit Testing\AsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package.

Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage:

using Nito.AsyncEx;
class Program
{
    static void Main(string[] args)
    {
        AsyncContext.Run(() => MainAsync(args));
    }

    static async void MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

Alternatively, you can just block the main Console thread until your asynchronous work has completed:

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).GetAwaiter().GetResult();
    }

    static async Task MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.

Liam
  • 27,717
  • 28
  • 128
  • 190
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 36
    You *can* use a simple `Wait` or `Result`, and there's nothing wrong with that. But be aware that there are two important differences: 1) all `async` continuations run on the thread pool rather than the main thread, and 2) any exceptions are wrapped in an `AggregateException`. – Stephen Cleary May 22 '14 at 14:32
  • 3
    Was having a real problem figuring this out until this (and your blog post). This is by far the easiest method to solve this problem, and you can install the package in the nuget console with just a "install-package Nito.Asyncex" and you are done. – ConstantineK Jan 05 '16 at 06:35
  • 1
    My problem with these solutions is that the debugger (Visual Studio 2017 15.3.1) breaks in the Main method, not on the location where the Exception is thrown, and the Call Stack window is empty. – Greg Aug 21 '17 at 19:00
  • @Greg: If you want to break when the exception is thrown, then select "Break when Thrown" for the appropriate category in the Exception Settings window. – Stephen Cleary Aug 21 '17 at 19:41
  • 1
    @StephenCleary: Thanks for the fast response Stephen. I don't understand why anyone *wouldn't* want the debugger to break when an exception is thrown. If I'm debugging and run across a null reference exception, going directly to the offending line of code seems preferred. VS works like that "out of the box" for synchronous code, but not for async/await. – Greg Aug 21 '17 at 19:51
  • 10
    C# 7.1 has a async main now, might be worth adding to your great answer, @StephenCleary https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md – Mafii Nov 30 '17 at 14:19
  • 1
    @greg This is probably because [some libraries use exceptions for control flow](https://softwareengineering.stackexchange.com/q/189222/83653), in which case you don’t want to break for exceptions because there will be a lot and they will all be “expected” or part of normal operation. VS does mostly address this issue with the Just My Code feature, though. – binki Mar 01 '18 at 15:30
  • 3
    If your using the C# 7.1 version in VS 2017 I needed to ensure the project was configured to use the latest version of the language by adding `latest` into the csproj file, as [shown here](https://stackoverflow.com/a/45958948/542251). – Liam Jul 09 '18 at 12:25
  • Unfortunately, a similar update to allow `Async Main` has not been provided for VB. – Craig Feb 13 '19 at 20:19
  • However, it's not possible to select async main in project options/Application/Startup object. – Alex May 28 '19 at 13:25
  • As of January 2021 this feature is marked as a "proposal". It has been almost 3 years since it was documented on the Microsoft page that describes it. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main – H2ONaCl Jan 31 '21 at 02:40
  • This feature appears to be a misnomer because it is called "async Main" . The adjective does not apply because it's really a "Task Main" declaration. The feature is documented wrong where it says... "Allow await to be used in an application's Main / entrypoint method". If you try to use "await" you will get the CS4032 error that await can only be used within an async method. The document is silent on how the command line is supposed to receive Task and Task which is a bizarre oversight. The least they could do is to write "invoke it the same as you would "void Main". – H2ONaCl Jan 31 '21 at 02:40
  • This feature is misnamed and wrongly described and incompletely described. I am angry because it wouldn't take much to have avoided these shortcomings. Reading Microsoft documents is to strike a balance between acceptance and skepticism and to continually adjust. – H2ONaCl Jan 31 '21 at 02:53
  • @H2ONaCl: I believe all the MS docs are open-source now, and they take pull requests. – Stephen Cleary Feb 01 '21 at 00:59
393

You can solve this with this simple construct:

class Program
{
    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            // Do any async anything you need here without worry
        }).GetAwaiter().GetResult();
    }
}

That will put everything you do out on the ThreadPool where you'd want it (so other Tasks you start/await don't attempt to rejoin a Thread they shouldn't), and wait until everything's done before closing the Console app. No need for special loops or outside libs.

Edit: Incorporate Andrew's solution for uncaught Exceptions.

Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
  • 3
    This approach is very obvious but tends to wrap exceptions so I'm looking now for a better way. – abatishchev Jan 28 '15 at 17:18
  • 2
    @abatishchev You should be using try/catch in your code, at least inside the Task.Run if not more granularly, not letting exceptions float up to the Task. You'll avoid the wrap up problem by putting try/catch around things that can fail. – Chris Moschini Mar 23 '15 at 22:25
  • 57
    If you replace `Wait()` with `GetAwaiter().GetResult()` you'll avoid the `AggregateException` wrapper when things throw. – Andrew Arnott Nov 19 '15 at 23:26
  • 7
    This is how `async main` is being introduced in C# 7.1, as of this writing. – user9993 Jun 14 '17 at 12:03
  • @user9993 According to [this proposal](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md), that's not exactly true. – Sinjai Jan 17 '19 at 22:24
92

You can do this without needing external libraries also by doing the following:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>

        Task.WaitAll(getListTask); // block while the task completes

        var list = getListTask.Result;
    }
}
p.campbell
  • 98,673
  • 67
  • 256
  • 322
Steven Evers
  • 16,649
  • 19
  • 79
  • 126
  • 7
    Bear in mind that `getListTask.Result` is also a blocking call and so the above code could be written without `Task.WaitAll(getListTask)`. – do0g Jul 12 '14 at 04:52
  • 27
    Also, if `GetList` throws you will have to catch an `AggregateException` and interrogate its exceptions to determine the actual exception thrown. You can, however, call `GetAwaiter()` to get the `TaskAwaiter` for the `Task`, and call `GetResult()` on that, ie `var list = getListTask.GetAwaiter().GetResult();`. When getting the result from the `TaskAwaiter` (also a blocking call) any exceptions thrown will not be wrapped in an `AggregateException`. – do0g Jul 12 '14 at 04:57
  • 1
    .GetAwaiter().GetResult was the answer I needed. That works perfectly for what I was attempting to do. I will probably use this in other places as well. – Deathstalker Jan 23 '17 at 23:12
90

In C# 7.1 you will be able to do a proper async Main. The appropriate signatures for Main method has been extended to:

public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);

For e.g. you could be doing:

static async Task Main(string[] args)
{
    Bootstrapper bs = new Bootstrapper();
    var list = await bs.GetList();
}

At compile time, the async entry point method will be translated to call GetAwaitor().GetResult().

Details: https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main

EDIT:

To enable C# 7.1 language features, you need to right-click on the project and click "Properties" then go to the "Build" tab. There, click the advanced button at the bottom:

enter image description here

From the language version drop-down menu, select "7.1" (or any higher value):

enter image description here

The default is "latest major version" which would evaluate (at the time of this writing) to C# 7.0, which does not support async main in console apps.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • 2
    FWIW this is available in Visual Studio 15.3 and up, which is currently available as a beta/preview release from here: https://www.visualstudio.com/vs/preview/ – Mahmoud Al-Qudsi Jul 10 '17 at 17:25
  • Wait a minute... I'm running a fully updated install and my latest option is 7.1... how'd you get 7.2 already in May? –  Nov 15 '17 at 21:12
  • May answer was mine. October edit was by someone else by the time I think 7.2 (preview?) might have got released. – nawfal Nov 16 '17 at 03:20
  • For an example have a look at this GitHub repo: https://github.com/nicknijenhuis/ChromeCastBackgroundSyncer – Nick N. May 14 '18 at 10:59
  • 1
    Heads up - check that it is on all configs, not just debug when you do this! – user230910 Aug 22 '18 at 04:42
  • 1
    @user230910 thanks. One of the weirdest choices by c# team. – nawfal Aug 22 '18 at 04:58
82

I'll add an important feature that all of the other answers have overlooked: cancellation.

One of the big things in TPL is cancellation support, and console apps have a method of cancellation built in (CTRL+C). It's very simple to bind them together. This is how I structure all of my async console apps:

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    
    System.Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = true;
        cts.Cancel();
    };

    MainAsync(args, cts.Token).GetAwaiter.GetResult();
}

static async Task MainAsync(string[] args, CancellationToken token)
{
    ...
}
Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • 1
    Should the cancellation token be passed to the `Wait()` as well? – Siewers Oct 14 '14 at 19:03
  • 5
    No, because you want the async code a be able to gracefully handle the cancellation. If you pass it to the `Wait()`, it won't wait for the async code to finish -- it'll stop waiting and end the process immediately. – Cory Nelson Oct 14 '14 at 19:57
  • Are you sure about that? I've just tried it out, and it seems like the cancellation request is being processed at the deepest level, even when the `Wait()` method is passed the same token. What I'm trying to say is, that it doesn't seem to make any difference. – Siewers Oct 14 '14 at 20:00
  • 4
    I'm sure. You want to cancel the op itself, not the wait for the op to finish. Unless you don't care about cleanup code finishing or the result of it. – Cory Nelson Oct 14 '14 at 21:24
  • 1
    Yeah, I think I get it, it just didn't seem to make any difference in my code. Another thing that threw me off course was a polite ReSharper hint about the wait method supporting cancellation ;) You might want to include a try catch in the example, as it will throw an OperationCancelledException, which I couldn't figure out at first – Siewers Oct 14 '14 at 22:14
  • @Siewers In your code, you’re probably synchronously handling the cancellation somehow. There are situations where a token will be cancelled but you will still wait for some task to complete prior to throwing `OperationCanceledException`. If you did that, you should notice a difference in behavior because passing the token to `Wait()` would cause it to abort prior to your program’s `Task` completing. – binki Mar 01 '18 at 15:33
26

C# 7.1 (using vs 2017 update 3) introduces async main

You can write:

   static async Task Main(string[] args)
  {
    await ...
  }

For more details C# 7 Series, Part 2: Async Main

Update:

You may get a compilation error:

Program does not contain a static 'Main' method suitable for an entry point

This error is due to that vs2017.3 is configured by default as c#7.0 not c#7.1.

You should explicitly modify the setting of your project to set c#7.1 features.

You can set c#7.1 by two methods:

Method 1: Using the project settings window:

  • Open the settings of your project
  • Select the Build tab
  • Click the Advanced button
  • Select the version you want As shown in the following figure:

enter image description here

Method2: Modify PropertyGroup of .csproj manually

Add this property:

    <LangVersion>7.1</LangVersion>

example:

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <PlatformTarget>AnyCPU</PlatformTarget>
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
        <Prefer32Bit>false</Prefer32Bit>
        <LangVersion>7.1</LangVersion>
    </PropertyGroup>    
M.Hassan
  • 10,282
  • 5
  • 65
  • 84
20

If you're using C# 7.1 or later, go with the nawfal's answer and just change the return type of your Main method to Task or Task<int>. If you are not:

  • Have an async Task MainAsync like Johan said.
  • Call its .GetAwaiter().GetResult() to catch the underlying exception like do0g said.
  • Support cancellation like Cory said.
  • A second CTRL+C should terminate the process immediately. (Thanks binki!)
  • Handle OperationCancelledException - return an appropriate error code.

The final code looks like:

private static int Main(string[] args)
{
    var cts = new CancellationTokenSource();
    Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = !cts.IsCancellationRequested;
        cts.Cancel();
    };

    try
    {
        return MainAsync(args, cts.Token).GetAwaiter().GetResult();
    }
    catch (OperationCanceledException)
    {
        return 1223; // Cancelled.
    }
}

private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
    // Your code...

    return await Task.FromResult(0); // Success.
}
Şafak Gür
  • 7,045
  • 5
  • 59
  • 96
  • 1
    Many nice programs will cancel the CancelKeyPress only the first time so that if you press ^C once you get a graceful shutdown but if you’re impatient a second ^C terminates ungracefully. With this solution, you’d need to manually kill the program if it fails to honor the CancellationToken because `e.Cancel = true` is unconditional. – binki Mar 01 '18 at 15:37
19

Haven't needed this much yet, but when I've used console application for Quick tests and required async I've just solved it like this:

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).Wait();
    }

    static async Task MainAsync(string[] args)
    {
        // Code here
    }
}
Johan Falk
  • 4,341
  • 2
  • 30
  • 42
  • This example will work wrong in case when you have to schedule task to current context and then wait it (for example, you can forget to add ConfigureAwait(false), so return method will be scheduled into the main thread, which is in Wait function). Because the current thread is in wait state, you will receive a deadlock. – Manushin Igor Sep 23 '15 at 13:54
  • 7
    Not true, @ManushinIgor. At least in this trivial example, there is no `SynchronizationContext` associated with the main thread. So it won't deadlock because even without `ConfigureAwait(false)`, all continuations will execute on the threadpool. – Andrew Arnott Nov 19 '15 at 23:27
7

For asynchronously calling task from Main, use

  1. Task.Run() for .NET 4.5

  2. Task.Factory.StartNew() for .NET 4.0 (May require Microsoft.Bcl.Async library for async and await keywords)

Details: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

user3408030
  • 71
  • 1
  • 2
4

In Main try changing the call to GetList to:

Task.Run(() => bs.GetList());
Fredrik Ljung
  • 1,445
  • 13
  • 28
4

Newest version of C# - C# 7.1 allows to create async console app. To enable C# 7.1 in project, you have to upgrade your VS to at least 15.3, and change C# version to C# 7.1 or C# latest minor version. To do this, go to Project properties -> Build -> Advanced -> Language version.

After this, following code will work:

internal class Program
{
    public static async Task Main(string[] args)
    {
         (...)
    }
Kedrzu
  • 623
  • 5
  • 12
4

As of C# 7.1 the following signatures are valid for the Main method.

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

So, now you can do async/await

static async Task Main(string[] args)
{
    Console.WriteLine("Hello Asyn Main method!");
    await Task.Delay(200);
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
DanKodi
  • 3,550
  • 27
  • 26
4

When the C# 5 CTP was introduced, you certainly could mark Main with async... although it was generally not a good idea to do so. I believe this was changed by the release of VS 2013 to become an error.

Unless you've started any other foreground threads, your program will exit when Main completes, even if it's started some background work.

What are you really trying to do? Note that your GetList() method really doesn't need to be async at the moment - it's adding an extra layer for no real reason. It's logically equivalent to (but more complicated than):

public Task<List<TvChannel>> GetList()
{
    return new GetPrograms().DownloadTvChannels();
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Jon, I want to get the items in the list asynchronously, so why is the async not appropriate on that GetList method ? Is it because I need to collect the items in the list async' and not the list itself ? When I try to mark the Main method with async I get a "does not contain a static Main method..." – danielovich Feb 09 '12 at 10:28
  • @danielovich: What does `DownloadTvChannels()` return? Presumably it returns a `Task>` doesn't it? If not, it's unlikely that you'd be able to await it. (Possible, given the awaiter pattern, but unlikely.) As for the `Main` method - it still needs to be static... did you *replace* the `static` modifier with the `async` modifier perhaps? – Jon Skeet Feb 09 '12 at 10:34
  • yes, it returns a Task<..> like you said. No matter how I try to put async in the Main method signature it throws an error. I am sitting on VS11 preview bits! – danielovich Feb 09 '12 at 11:08
  • @danielovich: Even with a void return type? Just `public static async void Main() {}`? But if `DownloadTvChannels()` already returns a `Task>`, presumably it's already asynchronous - so you don't need to add another layer. It's worth understanding this carefully. – Jon Skeet Feb 09 '12 at 11:09
  • yes, it's not working no matter what! That was why I tried to do another abstraction on top... – danielovich Feb 09 '12 at 11:34
  • @danielovich: Okay, I'll try with the VS11 Preview at home tonight, but it definitely worked with the CTP. But as I say, you usually don't want to do that anyway - and you *don't* need your method to be an async method. It's not clear you really need your method anyway. What are you trying to achieve with your console app? Currently it will start fetching the TV channels but then terminate immediately, which is presumably not really what you want. – Jon Skeet Feb 09 '12 at 11:37
  • @danielovich: Yes, it's worth diving into it in detail rather than using it just from examples. You may want to read my blog posts on it (http://msmvps.com/blogs/jon_skeet/archive/tags/async/default.aspx) as well as those by Eric Lippert, Mads Torgersen, Stephen Toub etc. – Jon Skeet Feb 09 '12 at 11:54
  • @JonSkeet, I'd be curious to hear more about the foreground thread approach. – Jess May 22 '14 at 14:37
  • @JonSkeet "it's adding an extra layer for no real reason" Is there any reason to use async/await throughout a console application, if I use ````Task.Wait()```` in ````Main```` anyway? E. g., if you use an async-only library like ````HttpClient````, should you make all calling methods async, too, and use ````Task.Wait()```` in ````Main```` or should you directly use ````Task.Wait()```` in the first method invoking a method of ````HttpClient````? – Niklas Peter Oct 18 '16 at 07:55
  • @NiklasPeter: If you're working with naturally-async APIs, it's typically cleaner to write your code in terms of async as well, and have one "switching" point where you wait for the result, rather than calling `Wait()` or `Result` all over the place. (Blocking for a task's completion is also dangerous in certain contexts, due to re-entrancy - so you want to do it in as few places as possible, and think about them carefully.) – Jon Skeet Oct 18 '16 at 08:07
  • If you mark Main method with async keyword I reckon it wont compile? What do you mean by your first line Jon? – nawfal Nov 21 '16 at 08:46
  • @nawfal: When I wrote the answer, that compiled. I believe C# 6 changed that... it's possible that C# 7 will change it back again. – Jon Skeet Nov 21 '16 at 08:47
  • 1
    @nawfal: Looking back, I think it changed before VS2013 was released. Not sure if C# 7 will be changing that... – Jon Skeet Nov 21 '16 at 08:50
3

On MSDN, the documentation for Task.Run Method (Action) provides this example which shows how to run a method asynchronously from main:

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
    public static void Main()
    {
        ShowThreadInfo("Application");

        var t = Task.Run(() => ShowThreadInfo("Task") );
        t.Wait();
    }

    static void ShowThreadInfo(String s)
    {
        Console.WriteLine("{0} Thread ID: {1}",
                          s, Thread.CurrentThread.ManagedThreadId);
    }
}
// The example displays the following output:
//       Application thread ID: 1
//       Task thread ID: 3

Note this statement that follows the example:

The examples show that the asynchronous task executes on a different thread than the main application thread.

So, if instead you want the task to run on the main application thread, see the answer by @StephenCleary.

And regarding the thread on which the task runs, also note Stephen's comment on his answer:

You can use a simple Wait or Result, and there's nothing wrong with that. But be aware that there are two important differences: 1) all async continuations run on the thread pool rather than the main thread, and 2) any exceptions are wrapped in an AggregateException.

(See Exception Handling (Task Parallel Library) for how to incorporate exception handling to deal with an AggregateException.)


Finally, on MSDN from the documentation for Task.Delay Method (TimeSpan), this example shows how to run an asynchronous task that returns a value:

using System;
using System.Threading.Tasks;

public class Example
{
    public static void Main()
    {
        var t = Task.Run(async delegate
                {
                    await Task.Delay(TimeSpan.FromSeconds(1.5));
                    return 42;
                });
        t.Wait();
        Console.WriteLine("Task t Status: {0}, Result: {1}",
                          t.Status, t.Result);
    }
}
// The example displays the following output:
//        Task t Status: RanToCompletion, Result: 42

Note that instead of passing a delegate to Task.Run, you can instead pass a lambda function like this:

var t = Task.Run(async () =>
        {
            await Task.Delay(TimeSpan.FromSeconds(1.5));
            return 42;
        });
Community
  • 1
  • 1
DavidRR
  • 18,291
  • 25
  • 109
  • 191
3

In my case I had a list of jobs that I wanted to run in async from my main method, have been using this in production for quite sometime and works fine.

static void Main(string[] args)
{
    Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult();
}
private static async Task RunMulti(List<string> joblist)
{
    await ...
}
user_v
  • 9,628
  • 4
  • 40
  • 32
1

To avoid freezing when you call a function somewhere down the call stack that tries to re-join the current thread (which is stuck in a Wait), you need to do the following:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result;
    }
}

(the cast is only required to resolve ambiguity)

Nathan Phillips
  • 11,899
  • 1
  • 31
  • 24
0
class Program
{
     public static EventHandler AsyncHandler;
     static void Main(string[] args)
     {
        AsyncHandler+= async (sender, eventArgs) => { await AsyncMain(); };
        AsyncHandler?.Invoke(null, null);
     }

     private async Task AsyncMain()
     {
        //Your Async Code
     }
}
0

This is hypothetical but I am thinking:

static void Main(string[] args)
{
    var context = new Thread(() => /*do stuff*/);
    context.Start();
    context.Join();
}
0

Not sure if this is what you're looking for, but I wanted to await a method on load. I ended up using the Main_Shown handler and making it async:

private async void Main_Shown(object sender, EventArgs e)
{
   await myAsyncMethod();
}
Andrew Gale
  • 101
  • 1
  • 4